diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/404.html b/404.html new file mode 100644 index 000000000000..04cd997203d4 --- /dev/null +++ b/404.html @@ -0,0 +1,16 @@ + + + + + +Page Not Found | etherealengine + + + + +
+
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.6c1ddb1d.css b/assets/css/styles.6c1ddb1d.css new file mode 100644 index 000000000000..8a2a4840cd7f --- /dev/null +++ b/assets/css/styles.6c1ddb1d.css @@ -0,0 +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)}[data-theme=dark] .DocSearch,[data-theme=light] .DocSearch{--docsearch-muted-color:var(--ifm-color-secondary-darkest);--docsearch-hit-color:var(--ifm-font-color-base);--docsearch-hit-active-color:var(--ifm-color-white)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}*,.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}: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:#01022e;--ifm-color-primary-dark:#29784c;--ifm-color-primary-darker:#277148;--ifm-color-primary-darkest:#205d3b;--ifm-color-primary-light:#33925d;--ifm-color-primary-lighter:#359962;--ifm-color-primary-lightest:#3cad6e;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base)}.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}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)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{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{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}.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;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;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)}.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);color:var(--ifm-font-color-base);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.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)}.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base);color:#fff!important}: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,.markdown a: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;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);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,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;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{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);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-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-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{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;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#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:#01022e;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--docusaurus-highlighted-code-line-bg:#0000004d}.docusaurus-highlight-code-line{background-color:#484d5b;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.markdown a{font-weight:500;text-decoration:underline}[data-theme=light] .DocSearch{--docsearch-container-background:#5e6470b3;--docsearch-modal-background:var(--ifm-color-secondary-lighter);--docsearch-searchbox-background:var(--ifm-color-secondary);--docsearch-searchbox-focus-background:var(--ifm-color-white);--docsearch-hit-background:var(--ifm-color-white);--docsearch-footer-background:var(--ifm-color-white)}[data-theme=dark] .DocSearch{--docsearch-text-color:var(--ifm-font-color-base);--docsearch-container-background:#2f3745b3;--docsearch-modal-background:var(--ifm-background-color);--docsearch-searchbox-background:var(--ifm-background-color);--docsearch-searchbox-focus-background:var(--ifm-color-black);--docsearch-hit-background:var(--ifm-color-emphasis-100);--docsearch-footer-background:var(--ifm-background-surface-color);--docsearch-key-gradient:linear-gradient(-26.5deg,var(--ifm-color-emphasis-200) 0%,var(--ifm-color-emphasis-100) 100%)}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.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}.DocSearch-Container a,.tag_zVej:hover{text-decoration:none}.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}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[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)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.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{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.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}.searchQueryInput_u2C7,.searchVersionInput_m0Ui{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_u2C7:focus,.searchVersionInput_m0Ui:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_u2C7::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_JPFH{font-size:.9rem;font-weight:700}.algoliaLogo_rT1R{max-width:150px}.algoliaLogoPathFill_WdUC{fill:var(--ifm-font-color-base)}.searchResultItem_Tv2o{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_KbCB{font-weight:400;margin-bottom:0}.searchResultItemPath_lhe1{--ifm-breadcrumb-separator-size-multiplier:1;color:var(--ifm-color-content-secondary);font-size:.8rem}.searchResultItemSummary_AEaO{font-style:italic;margin:.5rem 0 0}.loadingSpinner_XVxU{animation:1s linear infinite a;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes a{to{transform:rotate(1turn)}}.loader_vvXV{margin-top:2rem}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.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)}.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}.collapseSidebarButton_PEFL{display:none;margin:0}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}.heroBanner_qdFl{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_AeoN,.mdxPageWrapper_j9I6{justify-content:center}.DocSearch-Button,.DocSearch-Button-Container,.buttons_AeoN,.features_cAfv{align-items:center;display:flex}.features_cAfv{padding:2rem 0;text-align:center;width:100%}.featureImage_wMIZ{height:200px;width:200px}.hero--primary_JQ01{background-color:#01022e!important}.button_JGCe{color:#fff}.DocSearch-Button{background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Input,.DocSearch-Link{-webkit-appearance:none;font:inherit}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Hit-action-button,.DocSearch-Reset{-webkit-appearance:none;border:0;cursor:pointer}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards b;appearance:none;background:none;border-radius:50%;color:var(--docsearch-icon-color);padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border-radius:50%;color:inherit;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands li,.DocSearch-Commands-Key{align-items:center;display:flex}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}@keyframes b{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container{z-index:calc(var(--ifm-z-index-fixed) + 1)}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;list-style:none;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:"#"}.containsTaskList_mC6p{list-style:none}.img_ev3q{height:auto}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.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}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}: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)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_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%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_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)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.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}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.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 only screen and (max-width:996px){.searchQueryColumn_RTkw,.searchResultsColumn_JPFH{max-width:60%!important}.searchLogoColumn_rJIA,.searchVersionColumn_ypXd{max-width:40%!important}.searchLogoColumn_rJIA{padding-left:0!important}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{-webkit-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media screen and (max-width:576px){.searchQueryColumn_RTkw{max-width:100%!important}.searchVersionColumn_ypXd{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@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 (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width);animation:none;-webkit-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png b/assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png new file mode 100644 index 000000000000..e9a8ce173f2a Binary files /dev/null and b/assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png differ diff --git a/assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg b/assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg new file mode 100644 index 000000000000..812105e5bb2c Binary files /dev/null and b/assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg differ diff --git a/assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg b/assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg new file mode 100644 index 000000000000..2618f7eda64b Binary files /dev/null and b/assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg differ diff --git a/assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg b/assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg new file mode 100644 index 000000000000..f9fa57b8e795 Binary files /dev/null and b/assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg differ diff --git a/assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png b/assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png new file mode 100644 index 000000000000..3ebf610be08a Binary files /dev/null and b/assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png differ diff --git a/assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg b/assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg new file mode 100644 index 000000000000..283f50fb48e0 Binary files /dev/null and b/assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg differ diff --git a/assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg b/assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg new file mode 100644 index 000000000000..23c95a8735f2 Binary files /dev/null and b/assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg differ diff --git a/assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg b/assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg new file mode 100644 index 000000000000..84b578fb6eae Binary files /dev/null and b/assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg differ diff --git a/assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg b/assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg new file mode 100644 index 000000000000..f0195240d0a6 Binary files /dev/null and b/assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg differ diff --git a/assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg b/assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg new file mode 100644 index 000000000000..6618a75cc4b5 Binary files /dev/null and b/assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg differ diff --git a/assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg b/assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg new file mode 100644 index 000000000000..4bb069363c0c Binary files /dev/null and b/assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg differ diff --git a/assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg b/assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg new file mode 100644 index 000000000000..150330b21071 Binary files /dev/null and b/assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg differ diff --git a/assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg b/assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg new file mode 100644 index 000000000000..c4bd453225f8 Binary files /dev/null and b/assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg differ diff --git a/assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg b/assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg new file mode 100644 index 000000000000..fcee7c6bfa1a Binary files /dev/null and b/assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg differ diff --git a/assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg b/assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg new file mode 100644 index 000000000000..8f3980b70718 Binary files /dev/null and b/assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg differ diff --git a/assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg b/assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg new file mode 100644 index 000000000000..8ea7e8b4209c Binary files /dev/null and b/assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg differ diff --git a/assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg b/assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg new file mode 100644 index 000000000000..50862947d2e6 Binary files /dev/null and b/assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg differ diff --git a/assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg b/assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg new file mode 100644 index 000000000000..e653c196effb Binary files /dev/null and b/assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg differ diff --git a/assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png b/assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png new file mode 100644 index 000000000000..180c9eb66301 Binary files /dev/null and b/assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png differ diff --git a/assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png b/assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png new file mode 100644 index 000000000000..3150502b3c24 Binary files /dev/null and b/assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png differ diff --git a/assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png b/assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png new file mode 100644 index 000000000000..424a297f5067 Binary files /dev/null and b/assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png differ diff --git a/assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png b/assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png new file mode 100644 index 000000000000..c944d7ca3ec2 Binary files /dev/null and b/assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png differ diff --git a/assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png b/assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png new file mode 100644 index 000000000000..be9ec3c46285 Binary files /dev/null and b/assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png differ diff --git a/assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg b/assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg new file mode 100644 index 000000000000..f5731e866180 Binary files /dev/null and b/assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg differ diff --git a/assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg b/assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg new file mode 100644 index 000000000000..a51a914ca883 Binary files /dev/null and b/assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg differ diff --git a/assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg b/assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg new file mode 100644 index 000000000000..5bc868a9784c Binary files /dev/null and b/assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg differ diff --git a/assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg b/assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg new file mode 100644 index 000000000000..d5424a72e659 Binary files /dev/null and b/assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg differ diff --git a/assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg b/assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg new file mode 100644 index 000000000000..873f3202fe41 Binary files /dev/null and b/assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg differ diff --git a/assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg b/assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg new file mode 100644 index 000000000000..563b6364421a Binary files /dev/null and b/assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg differ diff --git a/assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg b/assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg new file mode 100644 index 000000000000..40bb9d674a15 Binary files /dev/null and b/assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg differ diff --git a/assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg b/assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg new file mode 100644 index 000000000000..2025da78c27f Binary files /dev/null and b/assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg differ diff --git a/assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg b/assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg new file mode 100644 index 000000000000..7b22c8ba97db Binary files /dev/null and b/assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg differ diff --git a/assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg b/assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg new file mode 100644 index 000000000000..9608ee30d7f1 Binary files /dev/null and b/assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg differ diff --git a/assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png b/assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png new file mode 100644 index 000000000000..cb2ba7a3ff77 Binary files /dev/null and b/assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png differ diff --git a/assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg b/assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg new file mode 100644 index 000000000000..72dd3c02db13 Binary files /dev/null and b/assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg differ diff --git a/assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg b/assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg new file mode 100644 index 000000000000..9334ccb8d3f1 Binary files /dev/null and b/assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg differ diff --git a/assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png b/assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png new file mode 100644 index 000000000000..4937f74d8562 Binary files /dev/null and b/assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png differ diff --git a/assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png b/assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png new file mode 100644 index 000000000000..3a33108a003e Binary files /dev/null and b/assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png differ diff --git a/assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png b/assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png new file mode 100644 index 000000000000..4dd09d97df27 Binary files /dev/null and b/assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png differ diff --git a/assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png b/assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png new file mode 100644 index 000000000000..b6e348900a5b Binary files /dev/null and b/assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png differ diff --git a/assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png b/assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png new file mode 100644 index 000000000000..b078df2480f0 Binary files /dev/null and b/assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png differ diff --git a/assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png b/assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png new file mode 100644 index 000000000000..f541b315f370 Binary files /dev/null and b/assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png differ diff --git a/assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png b/assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png new file mode 100644 index 000000000000..aca69f881efd Binary files /dev/null and b/assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png differ diff --git a/assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png b/assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png new file mode 100644 index 000000000000..7990acea71e5 Binary files /dev/null and b/assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png differ diff --git a/assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png b/assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png new file mode 100644 index 000000000000..961dbdce5aba Binary files /dev/null and b/assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png differ diff --git a/assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png b/assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png new file mode 100644 index 000000000000..30ba4ae3abab Binary files /dev/null and b/assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png differ diff --git a/assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png b/assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png new file mode 100644 index 000000000000..94d2e8260be9 Binary files /dev/null and b/assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png differ diff --git a/assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png b/assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png new file mode 100644 index 000000000000..a4aa61a36b4b Binary files /dev/null and b/assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png differ diff --git a/assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg b/assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg new file mode 100644 index 000000000000..010e45e55d67 Binary files /dev/null and b/assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg differ diff --git a/assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg b/assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg new file mode 100644 index 000000000000..e5fdfe4520c0 Binary files /dev/null and b/assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg differ diff --git a/assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png b/assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png new file mode 100644 index 000000000000..fd2d4224717d Binary files /dev/null and b/assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png differ diff --git a/assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg b/assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg new file mode 100644 index 000000000000..9a0339768cd7 Binary files /dev/null and b/assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg differ diff --git a/assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg b/assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg new file mode 100644 index 000000000000..41a80a0be699 Binary files /dev/null and b/assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg differ diff --git a/assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg b/assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg new file mode 100644 index 000000000000..a4cad46dd275 Binary files /dev/null and b/assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg differ diff --git a/assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg b/assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg new file mode 100644 index 000000000000..694bacff58f9 Binary files /dev/null and b/assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg differ diff --git a/assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png b/assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png new file mode 100644 index 000000000000..6d6e2a88a29f Binary files /dev/null and b/assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png differ diff --git a/assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg b/assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg new file mode 100644 index 000000000000..501d355ec101 Binary files /dev/null and b/assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg differ diff --git a/assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg b/assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg new file mode 100644 index 000000000000..db7ad2405cd9 Binary files /dev/null and b/assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg differ diff --git a/assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg b/assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg new file mode 100644 index 000000000000..370754935bbd Binary files /dev/null and b/assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg differ diff --git a/assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg b/assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg new file mode 100644 index 000000000000..fdbb001613e6 Binary files /dev/null and b/assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg differ diff --git a/assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg b/assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg new file mode 100644 index 000000000000..69927f6428d7 Binary files /dev/null and b/assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg differ diff --git a/assets/js/0304d7f4.46f13c57.js b/assets/js/0304d7f4.46f13c57.js new file mode 100644 index 000000000000..853717bded79 --- /dev/null +++ b/assets/js/0304d7f4.46f13c57.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8953],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>y});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),m=o,y=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(y,i(i({ref:t},p),{},{components:r})):n.createElement(y,i({ref:t},p))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={},i="Networking",s={unversionedId:"creator/development/networking",id:"creator/development/networking",title:"Networking",description:"Networks",source:"@site/docs/2_creator/4_development/3_networking.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/networking",permalink:"/etherealengine-docs/docs/creator/development/networking",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/3_networking.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Entities, Components and Systems",permalink:"/etherealengine-docs/docs/creator/development/ecs"},next:{title:"Event Sourcing",permalink:"/etherealengine-docs/docs/creator/development/actions_event_sourcing"}},c={},l=[{value:"Networks",id:"networks",level:2},{value:"Users & Peers",id:"users--peers",level:2},{value:"Ownership and Authority",id:"ownership-and-authority",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"networking"},"Networking"),(0,o.kt)("h2",{id:"networks"},"Networks"),(0,o.kt)("p",null,"Networks are a way of sharing topic specific data between certain peers. There are two types of networks, ",(0,o.kt)("strong",{parentName:"p"},"world")," and ",(0,o.kt)("strong",{parentName:"p"},"media")," networks, and are tied to location instances and media instances respectively."),(0,o.kt)("h2",{id:"users--peers"},"Users & Peers"),(0,o.kt)("p",null,"Users are unique accounts created in a particular Ethereal Engine deployment. Users can connect to multiple instances, and have multiple peers connected to each instance."),(0,o.kt)("h2",{id:"ownership-and-authority"},"Ownership and Authority"),(0,o.kt)("p",null,"Ownership specifies that a networked entity belongs to a particular user. Ownership cannot be transferred for an entity, the entity must be destroyed and recreated by a new user. "),(0,o.kt)("p",null,"Authority specifies that a networked entity can be controlled by a particular peer. Authority can be transferred between peers, and is done so by sending an authority request action to the owner peer, upon which the owner peer will send an authority transfer action to the requesting peer."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0346e14a.b3b01a5c.js b/assets/js/0346e14a.b3b01a5c.js new file mode 100644 index 000000000000..1c468416b5ef --- /dev/null +++ b/assets/js/0346e14a.b3b01a5c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[720],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=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 o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),u=i,m=p["".concat(s,".").concat(u)]||p[u]||h[u]||a;return n?o.createElement(m,r(r({ref:t},d),{},{components:n})):o.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,r=new Array(a);r[0]=u;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,r[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var o=n(7462),i=(n(7294),n(3905));const a={},r="Installing Projects",l={unversionedId:"host/devops_deployment/installing_projects",id:"host/devops_deployment/installing_projects",title:"Installing Projects",description:"Local Install Flow",source:"@site/docs/1_host/2_devops_deployment/2_installing_projects.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/installing_projects",permalink:"/etherealengine-docs/docs/host/devops_deployment/installing_projects",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/2_installing_projects.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on AWS",permalink:"/etherealengine-docs/docs/host/devops_deployment/AWS_setup"},next:{title:"Database Migrations",permalink:"/etherealengine-docs/docs/host/devops_deployment/database_migrations"}},s={},c=[{value:"Local Install Flow",id:"local-install-flow",level:2},{value:"Graphical Install Flow",id:"graphical-install-flow",level:2},{value:"Updating the Engine Version and Rebuilding Projects",id:"updating-the-engine-version-and-rebuilding-projects",level:3}],d={toc:c},p="wrapper";function h(e){let{components:t,...a}=e;return(0,i.kt)(p,(0,o.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"installing-projects"},"Installing Projects"),(0,i.kt)("h2",{id:"local-install-flow"},"Local Install Flow"),(0,i.kt)("p",null,"To install a project locally, clone the repository you wish to install to the\n",(0,i.kt)("inlineCode",{parentName:"p"},"/packages/projects/projects/")," folder. You can do this with the follow commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd packages/projects/projects/\ngit clone https://github.com/myorg/myrepo\ncd myrepo \ncode .\n")),(0,i.kt)("p",null,"This will create a folder name ",(0,i.kt)("inlineCode",{parentName:"p"},"myrepo")," which must contain an ",(0,i.kt)("inlineCode",{parentName:"p"},"xrengine.config.ts"),"\nfile, and open the project in a new vscode window (such that git commands can be\nhandled by the new window). All you need to do now to run this project is re-run\nthe stack (with ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev"),")."),(0,i.kt)("h2",{id:"graphical-install-flow"},"Graphical Install Flow"),(0,i.kt)("p",null,"Projects can also be installed and managed from the /admin/projects route. You must be\nan admin and must have a linked GitHub account, which can be attained by having your\nGitHub account linked to your Ethereal Engine account by signing in via GitHub.\n(You do not need to have most recently signed in via GitHub, you just have to have\nlinked your GH account at some point)"),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects"},"the section 'How to set up GitHub to install external projects'"),"\nfor instructions on creating an OAuth app from GitHub, installing it into an Ethereal Engine deployment,\nand authorizing it to have access to your GitHub organizations."),(0,i.kt)("p",null,"Click the 'Add Project' button:"),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(389).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"You will see text fields for entering the source and destination repositories.\nWhen you click away from the text fields, the URL will be checked both for the\nrepository existing, and for whether you have sufficient permission to access\nthat repository - read permission for the source repo (public repositories are\nalways available), and write or admin permission for the destination repo. If\nyou have never logged into GitHub with your current account, you will not be\nallowed to add or update projects."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(5752).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"For the source repository, after entering the URL, you will also need to select\na branch to pull from. Your options are either the main branch for that repository,\nor a branch that matches the ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," of the deployment, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"dev-deployment")," for\na deployment with the environment variable ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME=dev"),". If ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," is not defined, then\n",(0,i.kt)("inlineCode",{parentName:"p"},"local")," is used; this could lead to multiple local installations of the platform conflicting,\nbut one can set ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," locally to something else in your .env.local file."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(3571).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"After the branch is selected, you also need to select a tagged commit from that branch,\nor the most recent commit. As of this writing, you must manually tag project commits yourself,\nthough tags are copied over from the source repository when installing or updating a project."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(3792).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"The backend checks that the source and destination repos have the same project.\nThe project name is the ",(0,i.kt)("inlineCode",{parentName:"p"},"name")," field in the project's package.json file.\nIf the destination repo's ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment")," branch is empty or nonexistent, then\nany project can be uploaded to it. If the destination deployment branch is not empty,\nthen it can only be updated with different versions of that project. For example,\nif the destination branch has project ",(0,i.kt)("inlineCode",{parentName:"p"},"example1")," in it, you will not be allowed to\noverwrite it with a project ",(0,i.kt)("inlineCode",{parentName:"p"},"test3"),", only other projects named ",(0,i.kt)("inlineCode",{parentName:"p"},"example1"),"."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(8618).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"You can only install a project with a given name once, and names are ",(0,i.kt)("strong",{parentName:"p"},"case-insensitive"),";\n",(0,i.kt)("inlineCode",{parentName:"p"},"example1")," is seen as the same name as ",(0,i.kt)("inlineCode",{parentName:"p"},"ExamplE1"),". You would need to remove an existing project\nin order to install a different project that has the same name, or rename one of the projects."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(463).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"When everything is valid, you will be able to click the Submit button, which will install\nthe project."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(4548).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"Adding a project through this interface runs ",(0,i.kt)("inlineCode",{parentName:"p"},"git clone")," in the background, same as above,\nbut will then upload all of the repository's files to the storage provider. These files will then be\ndownloaded and installed to the deployment's file system each time the docker builder\npod runs. This allows full version controlled access for local development flow\nand version locking for production deployment. The source project code will then be force-pushed\nto the branch ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment"),", so make sure that there is no work in that branch\nthat might get overwritten, and make a backup in another branch you do want to save it."),(0,i.kt)("p",null,"The Push to GitHub button will push the current code for that project to the ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment"),"\nbranch if possible; it will ",(0,i.kt)("em",{parentName:"p"},"never")," push to the main branch. If there are merge conflicts, it will instead\nmake a Pull Request on that branch with the changes; it will NOT force-push anything to this branch,\nunlike adding or updating a project."),(0,i.kt)("p",null,"The Update button opens the same drawer as adding a new project, just with the destination repository locked in.\nAssuming everything matches, it will also force-push to the ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment")," branch in the destination\nrepository."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(8119).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"The GitHub Repo Link button also opens this drawer, but you can only select the destination repository, not\nthe source repository, and no code is pushed anywhere. "),(0,i.kt)("p",null,"The remove button will remove the folder containing that project. This will not delete the deployment\nbranch. WARNING: Any uncommitted & unpushed files will be lost."),(0,i.kt)("h3",{id:"updating-the-engine-version-and-rebuilding-projects"},"Updating the Engine Version and Rebuilding Projects"),(0,i.kt)("p",null,"Making changes to a project is not always reflected immediately in the running code. As of this writing,\nproject code is built into the client-side and backend files, and changes to project code require that\nthe codebase be updated. Locally, this just requires you to stop and restart the ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev")," command.\nIn a production environment, this requires that the builder process be restarted, so that it can\nrebuild the client and backend code with the new project code."),(0,i.kt)("p",null,"Changes to scenes in projects do not require a rebuild - since they are stored external to the codebase\nin the storage provider, and are downloaded anew by a client each time the scene is loaded, changes to\nscenes will always be immediately available. The act of saving a project will clear any cached version\nof the scene's static files, so the client will get the new version."),(0,i.kt)("p",null,"Additionally, if you want to update the core Ethereal Engine code, you will also need to re-run the builder\nprocess with the new version of the code."),(0,i.kt)("p",null,"In a production environment, click on the button ",(0,i.kt)("inlineCode",{parentName:"p"},"Update Engine/Rebuild"),". A drawer will open with\na selector for the engine version you want to update with. This will be an image in the builder's\nlinked image repository."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(800).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"After selecting an engine version, if you click Submit now, you will just rebuild with the\nnewly-selected version of the main codebase, plus whatever versions of your projects are currently\nin your linked repositories."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(372).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"If you click on ",(0,i.kt)("inlineCode",{parentName:"p"},"Update projects"),",\nyou can select the source commits for any installed projects that have a destination repo, same as with\nthe Add/Update project drawer. The projects will be updated before the builder is restarted."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(4273).Z,width:"1920",height:"960"})))}h.isMDXComponent=!0},800:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png"},372:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png"},4273:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png"},5752:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png"},8618:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png"},389:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png"},463:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png"},3571:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png"},3792:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png"},4548:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png"},8119:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png"}}]); \ No newline at end of file diff --git a/assets/js/06bf4b13.0975895e.js b/assets/js/06bf4b13.0975895e.js new file mode 100644 index 000000000000..0dc548136579 --- /dev/null +++ b/assets/js/06bf4b13.0975895e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5572],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>g});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 l(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 l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var i=r.createContext({}),c=function(e){var n=r.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return r.createElement(i.Provider,{value:n},e.children)},u="mdxType",h={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,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(t),d=a,g=u["".concat(i,".").concat(d)]||u[d]||h[d]||l;return t?r.createElement(g,o(o({ref:n},p),{},{components:t})):r.createElement(g,o({ref:n},p))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,o=new Array(l);o[0]=d;var s={};for(var i in n)hasOwnProperty.call(n,i)&&(s[i]=n[i]);s.originalType=e,s[u]="string"==typeof e?e:a,o[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>o,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var r=t(7462),a=(t(7294),t(3905));const l={},o="Logging with Opensearch on Docker",s={unversionedId:"host/installation/opensearch",id:"host/installation/opensearch",title:"Logging with Opensearch on Docker",description:"If you want to quickstart with detailed logging using opensearch, Please follow this guide.",source:"@site/docs/1_host/1_installation/8_opensearch.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/opensearch",permalink:"/etherealengine-docs/docs/host/installation/opensearch",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/8_opensearch.md",tags:[],version:"current",sidebarPosition:8,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Old Docker Instructions",permalink:"/etherealengine-docs/docs/host/installation/docker"},next:{title:"Deployment",permalink:"/etherealengine-docs/docs/host/devops_deployment/"}},i={},c=[{value:"Setup Opensearch on Docker locally",id:"setup-opensearch-on-docker-locally",level:2},{value:"Pull OpenSearch Images",id:"pull-opensearch-images",level:3},{value:"OpenSearch",id:"opensearch",level:4},{value:"OpenSearch Dashboard",id:"opensearch-dashboard",level:4},{value:"Start Opensearch Containers",id:"start-opensearch-containers",level:3},{value:"OpenSearch",id:"opensearch-1",level:4},{value:"OpenSearch Dashboard",id:"opensearch-dashboard-1",level:4},{value:"Verify if the containers are up & running",id:"verify-if-the-containers-are-up--running",level:3},{value:"Enable Client Logging",id:"enable-client-logging",level:3},{value:"Enable Server Logging",id:"enable-server-logging",level:3}],p={toc:c},u="wrapper";function h(e){let{components:n,...t}=e;return(0,a.kt)(u,(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"logging-with-opensearch-on-docker"},"Logging with Opensearch on Docker"),(0,a.kt)("p",null,"If you want to quickstart with detailed logging using opensearch, Please follow this guide. "),(0,a.kt)("h2",{id:"setup-opensearch-on-docker-locally"},"Setup Opensearch on Docker locally"),(0,a.kt)("h3",{id:"pull-opensearch-images"},"Pull OpenSearch Images"),(0,a.kt)("h4",{id:"opensearch"},"OpenSearch"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"docker pull opensearchproject/opensearch:latest\n")),(0,a.kt)("h4",{id:"opensearch-dashboard"},"OpenSearch Dashboard"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"docker pull opensearchproject/opensearch-dashboards:latest\n")),(0,a.kt)("h3",{id:"start-opensearch-containers"},"Start Opensearch Containers"),(0,a.kt)("h4",{id:"opensearch-1"},"OpenSearch"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" -e "plugins.security.disabled=true" opensearchproject/opensearch:latest \n')),(0,a.kt)("h4",{id:"opensearch-dashboard-1"},"OpenSearch Dashboard"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -it -d --network="host" -e "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true" opensearchproject/opensearch-dashboards:latest\n')),(0,a.kt)("h3",{id:"verify-if-the-containers-are-up--running"},"Verify if the containers are up & running"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Send a request to port 9200")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," curl http://127.0.0.1:9200\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"List Indices through curl ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},' curl -X GET "http://127.0.0.1:9200/_cat/indices?v"\n')),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Create Indices through Curl ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},' curl -X PUT "http://127.0.0.1:9200/your_index_name"\n')),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Delete Index ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," curl --location --request DELETE 'http://127.0.0.1:9200/index_name'\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Fetch logs for an index_name")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," curl --location --request GET 'http://127.0.0.1:9200/ethereal/_search' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"query\": {\n \"match_all\": {}\n },\n \"size\": 10000\n }'\n")),(0,a.kt)("h3",{id:"enable-client-logging"},"Enable Client Logging"),(0,a.kt)("p",null,"Set VITE_FORCE_CLIENT_LOG_AGGREGATE to true to enable client log aggregation"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"VITE_FORCE_CLIENT_LOG_AGGREGATE=true\n")),(0,a.kt)("h3",{id:"enable-server-logging"},"Enable Server Logging"),(0,a.kt)("p",null,"Set DISABLE_SERVER_LOG=false to false to enable server log aggregation "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"DISABLE_SERVER_LOG=false\n \n")),(0,a.kt)("p",null,"Note: These changes in the ",(0,a.kt)("inlineCode",{parentName:"p"},".env.local")," file will ensure proper communication with OpenSearch and enable client and server log aggregation"))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0991b023.bcdd8fa9.js b/assets/js/0991b023.bcdd8fa9.js new file mode 100644 index 000000000000..4967f809d976 --- /dev/null +++ b/assets/js/0991b023.bcdd8fa9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6524],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(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 a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={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,o=e.mdxType,c=e.originalType,s=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(r),f=o,m=u["".concat(s,".").concat(f)]||u[f]||d[f]||c;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=f;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:o,a[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>c,metadata:()=>i,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const c={},a="Concepts",i={unversionedId:"creator/concepts/readme",id:"creator/concepts/readme",title:"Concepts",description:"",source:"@site/docs/2_creator/1_concepts/readme.md",sourceDirName:"2_creator/1_concepts",slug:"/creator/concepts/",permalink:"/etherealengine-docs/docs/creator/concepts/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/1_concepts/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal for Creators",permalink:"/etherealengine-docs/docs/creator/"},next:{title:"Studio & Locations",permalink:"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations"}},s={},p=[],l={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"concepts"},"Concepts"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0f5dde8f.fe7a1c7a.js b/assets/js/0f5dde8f.fe7a1c7a.js new file mode 100644 index 000000000000..a9918a39a89e --- /dev/null +++ b/assets/js/0f5dde8f.fe7a1c7a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3976],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>m});var r=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 l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function d(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var o=r.createContext({}),s=function(e){var t=r.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):d(d({},t),e)),a},c=function(e){var t=s(e.components);return r.createElement(o.Provider,{value:t},e.children)},v="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,o=e.parentName,c=n(e,["components","mdxType","originalType","parentName"]),v=s(a),h=i,m=v["".concat(o,".").concat(h)]||v[h]||u[h]||l;return a?r.createElement(m,d(d({ref:t},c),{},{components:a})):r.createElement(m,d({ref:t},c))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,d=new Array(l);d[0]=h;var n={};for(var o in t)hasOwnProperty.call(t,o)&&(n[o]=t[o]);n.originalType=e,n[v]="string"==typeof e?e:i,d[1]=n;for(var s=2;s{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>d,default:()=>u,frontMatter:()=>l,metadata:()=>n,toc:()=>s});var r=a(7462),i=(a(7294),a(3905));const l={},d="Ethereal Engine Admin Panel Guide",n={unversionedId:"host/Admin_Dashboard/readme",id:"host/Admin_Dashboard/readme",title:"Ethereal Engine Admin Panel Guide",description:"Dashboard",source:"@site/docs/1_host/3_Admin_Dashboard/readme.md",sourceDirName:"1_host/3_Admin_Dashboard",slug:"/host/Admin_Dashboard/",permalink:"/etherealengine-docs/docs/host/Admin_Dashboard/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/3_Admin_Dashboard/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Getting Started",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started"},next:{title:"Ethereal for Creators",permalink:"/etherealengine-docs/docs/creator/"}},o={},s=[{value:"Dashboard",id:"dashboard",level:2},{value:"Usage Dashboard",id:"usage-dashboard",level:3},{value:"Usage Time Series",id:"usage-time-series",level:3},{value:"Projects",id:"projects",level:2},{value:"Managing Projects",id:"managing-projects",level:3},{value:"Project Table",id:"project-table",level:3},{value:"Name",id:"name",level:4},{value:"Version",id:"version",level:4},{value:"Commit SHA",id:"commit-sha",level:4},{value:"Commit Date",id:"commit-date",level:4},{value:"Update",id:"update",level:4},{value:"GitHub Integration",id:"github-integration",level:4},{value:"User Access",id:"user-access",level:4},{value:"Invalidate Cache",id:"invalidate-cache",level:4},{value:"View Project Files",id:"view-project-files",level:4},{value:"Routes",id:"routes",level:2},{value:"Location",id:"location",level:2},{value:"Create Location",id:"create-location",level:3},{value:"Name",id:"name-1",level:4},{value:"Max Users",id:"max-users",level:4},{value:"Scene",id:"scene",level:4},{value:"Type",id:"type",level:4},{value:"Media Toggles",id:"media-toggles",level:4},{value:"Make Lobby",id:"make-lobby",level:4},{value:"Featured",id:"featured",level:4},{value:"Location Table",id:"location-table",level:3},{value:"Instance",id:"instance",level:2},{value:"Patch InstanceServer",id:"patch-instanceserver",level:3},{value:"Instance Table",id:"instance-table",level:3},{value:"Instance Table Actions",id:"instance-table-actions",level:3},{value:"Users",id:"users",level:2},{value:"Create User",id:"create-user",level:3},{value:"Name",id:"name-2",level:4},{value:"Avatar",id:"avatar",level:4},{value:"Scopes",id:"scopes",level:4},{value:"Admin:Admin",id:"adminadmin",level:5},{value:"Benchmarking:read/write",id:"benchmarkingreadwrite",level:5},{value:"Bot:read/write",id:"botreadwrite",level:5},{value:"contentPacks:read/write",id:"contentpacksreadwrite",level:5},{value:"Editor:write",id:"editorwrite",level:5},{value:"globalAvatars:read/write",id:"globalavatarsreadwrite",level:5},{value:"Groups:read/write",id:"groupsreadwrite",level:5},{value:"Instance:read/write",id:"instancereadwrite",level:5},{value:"Invite:read",id:"inviteread",level:5},{value:"Location:read/write",id:"locationreadwrite",level:5},{value:"Party:read/write",id:"partyreadwrite",level:5},{value:"Projects:read/write",id:"projectsreadwrite",level:5},{value:"realityPacks:read/write",id:"realitypacksreadwrite",level:5},{value:"Recording:read/write",id:"recordingreadwrite",level:5},{value:"Routes:read/write",id:"routesreadwrite",level:5},{value:"Scene:read/write",id:"scenereadwrite",level:5},{value:"Server:read/write",id:"serverreadwrite",level:5},{value:"Settings:read/write",id:"settingsreadwrite",level:5},{value:"Static_resource:read/write",id:"static_resourcereadwrite",level:5},{value:"User:read/write",id:"userreadwrite",level:5},{value:"User Table",id:"user-table",level:3},{value:"Invites",id:"invites",level:2},{value:"Avatar",id:"avatar-1",level:2},{value:"Create Avatar",id:"create-avatar",level:3},{value:"Avatar Name",id:"avatar-name",level:4},{value:"File Source",id:"file-source",level:4},{value:"Avatar Thumbnail",id:"avatar-thumbnail",level:4},{value:"Avatar Table",id:"avatar-table",level:3},{value:"Resources",id:"resources",level:2},{value:"Create Resource",id:"create-resource",level:3},{value:"Name",id:"name-3",level:4},{value:"Project",id:"project",level:4},{value:"File Source",id:"file-source-1",level:4},{value:"Benchmarking",id:"benchmarking",level:2},{value:"Bots",id:"bots",level:2}],c={toc:s},v="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(v,(0,r.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"ethereal-engine-admin-panel-guide"},"Ethereal Engine Admin Panel Guide"),(0,i.kt)("h2",{id:"dashboard"},"Dashboard"),(0,i.kt)("h3",{id:"usage-dashboard"},"Usage Dashboard"),(0,i.kt)("h3",{id:"usage-time-series"},"Usage Time Series"),(0,i.kt)("h2",{id:"projects"},"Projects"),(0,i.kt)("h3",{id:"managing-projects"},"Managing Projects"),(0,i.kt)("h3",{id:"project-table"},"Project Table"),(0,i.kt)("h4",{id:"name"},"Name"),(0,i.kt)("h4",{id:"version"},"Version"),(0,i.kt)("h4",{id:"commit-sha"},"Commit SHA"),(0,i.kt)("h4",{id:"commit-date"},"Commit Date"),(0,i.kt)("h4",{id:"update"},"Update"),(0,i.kt)("h4",{id:"github-integration"},"GitHub Integration"),(0,i.kt)("h4",{id:"user-access"},"User Access"),(0,i.kt)("h4",{id:"invalidate-cache"},"Invalidate Cache"),(0,i.kt)("h4",{id:"view-project-files"},"View Project Files"),(0,i.kt)("h2",{id:"routes"},"Routes"),(0,i.kt)("h2",{id:"location"},"Location"),(0,i.kt)("h3",{id:"create-location"},"Create Location"),(0,i.kt)("h4",{id:"name-1"},"Name"),(0,i.kt)("h4",{id:"max-users"},"Max Users"),(0,i.kt)("h4",{id:"scene"},"Scene"),(0,i.kt)("h4",{id:"type"},"Type"),(0,i.kt)("h4",{id:"media-toggles"},"Media Toggles"),(0,i.kt)("h4",{id:"make-lobby"},"Make Lobby"),(0,i.kt)("h4",{id:"featured"},"Featured"),(0,i.kt)("h3",{id:"location-table"},"Location Table"),(0,i.kt)("h2",{id:"instance"},"Instance"),(0,i.kt)("h3",{id:"patch-instanceserver"},"Patch InstanceServer"),(0,i.kt)("h3",{id:"instance-table"},"Instance Table"),(0,i.kt)("h3",{id:"instance-table-actions"},"Instance Table Actions"),(0,i.kt)("h2",{id:"users"},"Users"),(0,i.kt)("h3",{id:"create-user"},"Create User"),(0,i.kt)("h4",{id:"name-2"},"Name"),(0,i.kt)("h4",{id:"avatar"},"Avatar"),(0,i.kt)("h4",{id:"scopes"},"Scopes"),(0,i.kt)("h5",{id:"adminadmin"},"Admin:Admin"),(0,i.kt)("h5",{id:"benchmarkingreadwrite"},"Benchmarking:read/write"),(0,i.kt)("h5",{id:"botreadwrite"},"Bot:read/write"),(0,i.kt)("h5",{id:"contentpacksreadwrite"},"contentPacks:read/write"),(0,i.kt)("h5",{id:"editorwrite"},"Editor:write"),(0,i.kt)("h5",{id:"globalavatarsreadwrite"},"globalAvatars:read/write"),(0,i.kt)("h5",{id:"groupsreadwrite"},"Groups:read/write"),(0,i.kt)("h5",{id:"instancereadwrite"},"Instance:read/write"),(0,i.kt)("h5",{id:"inviteread"},"Invite:read"),(0,i.kt)("h5",{id:"locationreadwrite"},"Location:read/write"),(0,i.kt)("h5",{id:"partyreadwrite"},"Party:read/write"),(0,i.kt)("h5",{id:"projectsreadwrite"},"Projects:read/write"),(0,i.kt)("h5",{id:"realitypacksreadwrite"},"realityPacks:read/write"),(0,i.kt)("h5",{id:"recordingreadwrite"},"Recording:read/write"),(0,i.kt)("h5",{id:"routesreadwrite"},"Routes:read/write"),(0,i.kt)("h5",{id:"scenereadwrite"},"Scene:read/write"),(0,i.kt)("h5",{id:"serverreadwrite"},"Server:read/write"),(0,i.kt)("h5",{id:"settingsreadwrite"},"Settings:read/write"),(0,i.kt)("h5",{id:"static_resourcereadwrite"},"Static_resource:read/write"),(0,i.kt)("h5",{id:"userreadwrite"},"User:read/write"),(0,i.kt)("h3",{id:"user-table"},"User Table"),(0,i.kt)("h2",{id:"invites"},"Invites"),(0,i.kt)("h2",{id:"avatar-1"},"Avatar"),(0,i.kt)("h3",{id:"create-avatar"},"Create Avatar"),(0,i.kt)("h4",{id:"avatar-name"},"Avatar Name"),(0,i.kt)("h4",{id:"file-source"},"File Source"),(0,i.kt)("h4",{id:"avatar-thumbnail"},"Avatar Thumbnail"),(0,i.kt)("h3",{id:"avatar-table"},"Avatar Table"),(0,i.kt)("h2",{id:"resources"},"Resources"),(0,i.kt)("h3",{id:"create-resource"},"Create Resource"),(0,i.kt)("h4",{id:"name-3"},"Name"),(0,i.kt)("h4",{id:"project"},"Project"),(0,i.kt)("h4",{id:"file-source-1"},"File Source"),(0,i.kt)("h2",{id:"benchmarking"},"Benchmarking"),(0,i.kt)("p",null,"In work"),(0,i.kt)("h2",{id:"bots"},"Bots"),(0,i.kt)("p",null,"In work"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/12905b1d.3d4cf35d.js b/assets/js/12905b1d.3d4cf35d.js new file mode 100644 index 000000000000..f7baf80ac08b --- /dev/null +++ b/assets/js/12905b1d.3d4cf35d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2345],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});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({}),h=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=h(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=h(n),d=o,g=p["".concat(l,".").concat(d)]||p[d]||c[d]||i;return n?a.createElement(g,r(r({ref:t},u),{},{components:n})):a.createElement(g,r({ref:t},u))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[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:o,r[1]=s;for(var h=2;h{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var a=n(7462),o=(n(7294),n(3905));const i={},r="How to set up GitHub to install external projects",s={unversionedId:"host/devops_deployment/setup_github_oauth_for_projects",id:"host/devops_deployment/setup_github_oauth_for_projects",title:"How to set up GitHub to install external projects",description:"Ethereal Engine is extensible via Projects, which can contain",source:"@site/docs/1_host/2_devops_deployment/4_setup_github_oauth_for_projects.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/setup_github_oauth_for_projects",permalink:"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/4_setup_github_oauth_for_projects.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Database Migrations",permalink:"/etherealengine-docs/docs/host/devops_deployment/database_migrations"},next:{title:"Cluster Management",permalink:"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes"}},l={},h=[{value:"Create a GitHub OAuth App in an organization, or your user",id:"create-a-github-oauth-app-in-an-organization-or-your-user",level:2},{value:"Create client secret, note Client ID",id:"create-client-secret-note-client-id",level:2},{value:"Make note of Client ID",id:"make-note-of-client-id",level:3},{value:"Generate client secret",id:"generate-client-secret",level:3},{value:"Configure Ethereal Engine deployment with IDs/keys",id:"configure-ethereal-engine-deployment-with-idskeys",level:2},{value:"Pre-initial installation",id:"pre-initial-installation",level:3},{value:"Post-installation, if you have another authentication method configured",id:"post-installation-if-you-have-another-authentication-method-configured",level:3},{value:"Post-installation, if you do not have any authentication method configured",id:"post-installation-if-you-do-not-have-any-authentication-method-configured",level:3},{value:"Setting up GitHub webhook",id:"setting-up-github-webhook",level:2}],u={toc:h},p="wrapper";function c(e){let{components:t,...i}=e;return(0,o.kt)(p,(0,a.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"how-to-set-up-github-to-install-external-projects"},"How to set up GitHub to install external projects"),(0,o.kt)("p",null,"Ethereal Engine is extensible via ",(0,o.kt)("a",{parentName:"p",href:"../3_concepts/1_projects_api.md"},"Projects"),", which can contain\nnew scenes, new avatars, new static resources, additional code, and more. Ethereal Engine integrates\nwith GitHub to push and pull projects for backup and restoration, and one can also install existing\nprojects from GitHub. In order to install projects from private repositories, or to push local project\nchanges to a GitHub repo, an OAuth app from GitHub (not a GitHub app, that is something different) needs to be\ncreated, and the logged-in user must be connected in Ethereal Engine to GitHub (i.e. must have logged in via\nGitHub at some point) and have permission to access the source and destination repositories."),(0,o.kt)("p",null,"Note that it is recommended that you complete most of this before the initial installation of\nyour deployment, so that you can log in via GitHub and be granted admin status as the first\nlogged-in user. If you do not, then you will either need to manually insert some of these values\ninto the database so that you can log yourself in; have another log method configured already\nand use that logged-in admin user; or reset the database with these values configured in the\nupdated Helm configuration that is used for the reset."),(0,o.kt)("h2",{id:"create-a-github-oauth-app-in-an-organization-or-your-user"},"Create a GitHub OAuth App in an organization, or your user"),(0,o.kt)("p",null,"You can either create an OAuth App for your personal GitHub account or for an organization that\nyou have sufficient permissions on. Either will work for this setup."),(0,o.kt)("p",null,"The general instructions for doing this can be found ",(0,o.kt)("a",{parentName:"p",href:"https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app"},"here"),".\nThe specifics you'll need to enter are as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Application name: Anything you want"),(0,o.kt)("li",{parentName:"ul"},"Homepage URL: Whatever you want, this is just what is linked to from the OAuth authorization page"),(0,o.kt)("li",{parentName:"ul"},"Authorization callback URL: enter ",(0,o.kt)("inlineCode",{parentName:"li"},"https://api./oauth/github/callback"),", e.g. ",(0,o.kt)("inlineCode",{parentName:"li"},"https://api.example.com/oauth/github/callback"),". ^ "),(0,o.kt)("li",{parentName:"ul"},"Enable Device Flow: Leave unchecked")),(0,o.kt)("p",null,"^If you are running this locally off of localhost, this should be ",(0,o.kt)("inlineCode",{parentName:"p"},"https://localhost:3030/oauth/github/callback"),".\nIf you are using an explicit IP address instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"localhost"),", then use that IP address here, but keep the ",(0,o.kt)("inlineCode",{parentName:"p"},":3030"),",\nas that is the port that the API server runs on, and GitHub needs to call back to the API server."),(0,o.kt)("h2",{id:"create-client-secret-note-client-id"},"Create client secret, note Client ID"),(0,o.kt)("p",null,"Once the app has been created, you will be redirected to the General settings for it.\nHere, you will generate one credential for the app, so that your deployment can be authenticated."),(0,o.kt)("h3",{id:"make-note-of-client-id"},"Make note of Client ID"),(0,o.kt)("p",null,"Near the top of this page is the Client ID for the app. This is a public ID for the app.\nIt will be used when configuring Ethereal Engine."),(0,o.kt)("h3",{id:"generate-client-secret"},"Generate client secret"),(0,o.kt)("p",null,"Below ",(0,o.kt)("inlineCode",{parentName:"p"},"Client ID")," is a section ",(0,o.kt)("inlineCode",{parentName:"p"},"Client secrets"),". None are created by default, so click the\nbutton ",(0,o.kt)("inlineCode",{parentName:"p"},"Generate a new client secret"),". As the notifications that appear say, you will only see the\nfull secret right now, so copy it somewhere retrievable (but not anywhere publicly accessible). If\nyou ever lose the secret, you can always generate a new one."),(0,o.kt)("h2",{id:"configure-ethereal-engine-deployment-with-idskeys"},"Configure Ethereal Engine deployment with IDs/keys"),(0,o.kt)("h3",{id:"pre-initial-installation"},"Pre-initial installation"),(0,o.kt)("p",null,"If you have not done the initial installation/deployment yet, then you can add most of the values\nabove to the Helm configuration, and they will be inserted into the database so that GitHub login\nis enabled from the start, and you can then log in via GitHub and be granted admin status."),(0,o.kt)("p",null,"Enter the Client ID for ",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT_ID"),", and the Client secret for\n",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT SECRET")," in the section ",(0,o.kt)("inlineCode",{parentName:"p"},"api.extraEnv"),". It is advised that you enclose all of these in\ndouble quotes in the .yaml file, so that they are interpreted as strings even if they start with a\nnumber, e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},'GITHUB_CLIENT_ID: "17592577832789234"')," If you see ",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_APP_ID"),", it is not used;\nit is left over from a prior implementation of GitHub Apps, which no longer works."),(0,o.kt)("p",null,"Continue with the setup instructions. When you run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install")," with your configuration file, the\nGitHub credentials will be included."),(0,o.kt)("h3",{id:"post-installation-if-you-have-another-authentication-method-configured"},"Post-installation, if you have another authentication method configured"),(0,o.kt)("p",null,"If you have already installed the platform but configured it with another login method, such as\nemail or another OAuth provider, then log in as an admin user. If you haven't logged in with anything\nyet, then the first user that logs in will be made an admin."),(0,o.kt)("p",null,"Go to ",(0,o.kt)("inlineCode",{parentName:"p"},"/admin/settings"),". Click on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Authentication")," selector. A page should open with a\nsection ",(0,o.kt)("inlineCode",{parentName:"p"},"OAuth")," that takes up the bottom two-thirds. Under ",(0,o.kt)("inlineCode",{parentName:"p"},"GitHub"),", enter\nthe Client ID under ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," and the Client Secret under ",(0,o.kt)("inlineCode",{parentName:"p"},"Secret"),". Click the Save button at the bottom."),(0,o.kt)("h3",{id:"post-installation-if-you-do-not-have-any-authentication-method-configured"},"Post-installation, if you do not have any authentication method configured"),(0,o.kt)("p",null,"If you have already set up the platform but did not configure any authentication method,\nthen you are in a bit of a bind where you can't log in to get admin privileges, but need admin\nprivileges to configure an authentication method. The way around this is to reset the database\nand provide the GitHub credentials as part of this process - this is similar to what would happen\non initial installation. Note that this will erase anything you've done so far, but without any\nadmins, the most you'd have been likely to do is change some guest users' avatars."),(0,o.kt)("p",null,"Open your Helm configuration. Enter the Client ID for ",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT_ID")," and the Client secret for\n",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT SECRET")," in the section ",(0,o.kt)("inlineCode",{parentName:"p"},"api.extraEnv"),". It is advised that you enclose all of these in\ndouble quotes in the .yaml file, so that they are interpreted as strings even if they start with a\nnumber, e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},'GITHUB_CLIENT_ID: "17592577832789234"')),(0,o.kt)("p",null,"Next, run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f --set-string api.extraEnv.FORCE_DB_REFRESH=true etherealengine/etherealengine"),".\nThis tells Helm to restart the API servers, and for them to wipe the database and reseed it with the values\nin the configuration file. It should only take a minute or two, and you should then run\n",(0,o.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values --set-string api.extraEnv.FORCE_DB_REFRESH=false etherealengine/etherealengine")," to unset\nthe flag telling it to reset the database."),(0,o.kt)("p",null,"Once this is done, you should be able to log in with GitHub and be granted admin status."),(0,o.kt)("h1",{id:"logging-in-with-github-and-granting-access-to-other-organizations"},"Logging in with GitHub and Granting Access to Other Organizations"),(0,o.kt)("p",null,"When you log in with GitHub, you will be asked to grant access to your user information as well as the repositories\nthat the OAuth app has authorized for. Ethereal Engine will have access to your personal repositories and,\nif the OAuth app was created in a GitHub organization, all repositories in that organization. It will not\nhave inherent push access to other organizations' repositories or pull access to their private repositories."),(0,o.kt)("p",null,"There are two ways to grant access to other repositories. When you are first signing in via GitHub and are\npresented with the screen to authorize the OAuth app's permissions, you should see a section near the bottom\nthat shows all of the organizations you are in. If you have admin rights to that organization, you can Grant\naccess. If you do not have admin rights, then you can Request access, and someone who does have admin rights\nwill have to approve it."),(0,o.kt)("p",null,(0,o.kt)("img",{src:n(1413).Z,width:"638",height:"1162"})),(0,o.kt)("p",null,"If you have already gone through the OAuth approval page, it will not be shown again - all subsequent logins\nwill bypass this page",(0,o.kt)("sup",{parentName:"p",id:"fnref-1"},(0,o.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),". In order to grant the OAuth app access to other organizations, follow\n",(0,o.kt)("a",{parentName:"p",href:"https://docs.github.com/en/organizations/managing-oauth-access-to-your-organizations-data/approving-oauth-apps-for-your-organization"},"these steps")),(0,o.kt)("p",null,"In short form:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Go to (",(0,o.kt)("a",{parentName:"li",href:"https://github.com/settings/applications"},"https://github.com/settings/applications"),")"),(0,o.kt)("li",{parentName:"ol"},"Click on the name of the OAuth app installed in Ethereal Engine"),(0,o.kt)("li",{parentName:"ol"},"Under ",(0,o.kt)("inlineCode",{parentName:"li"},"Organization access"),", click on Grant/Request for the organizations you want Ethereal Engine to\nhave access to")),(0,o.kt)("h1",{id:"installing-ethereal-engine-projects-from-github"},"Installing Ethereal Engine projects from GitHub"),(0,o.kt)("p",null,"See ",(0,o.kt)("a",{parentName:"p",href:"../3_concepts/1_projects_api.md"},"the section 'Graphical Install Flow")," for more information on how to install\nprojects from GitHub."),(0,o.kt)("h1",{id:"user-repo-access-to-github-with-optional-webhooks"},"User Repo Access to GitHub (with optional webhooks)"),(0,o.kt)("p",null,"Users can push projects to GitHub if they have write/maintain/admin access to the associated GitHub repository.\nSince fetching this access from the GitHub API every time a user fetches their projects can take a noticeable\namount of time, Ethereal Engine stores users' GitHub repo access in its database. This is much faster to access."),(0,o.kt)("p",null,"There are multiple actions that will make the engine re-fetch and update users' repo access:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"When a user logs in via GitHub"),(0,o.kt)("li",{parentName:"ul"},'When a user clicks on the button "Refresh GitHub Repo Access" on /admin/projects or /studio (must be logged\nin as a user that is associated with a GitHub account)'),(0,o.kt)("li",{parentName:"ul"},"Via a GitHub webhook - must manually configure this")),(0,o.kt)("h2",{id:"setting-up-github-webhook"},"Setting up GitHub webhook"),(0,o.kt)("p",null,"Ethereal Engine currently only supports webhook notifications for Collaborators being added/edited/removed.\nChanges in Teams are not handled by Ethereal Engine due to the opacity of team members. (Team change webhooks do not\ninclude team members, and the engine does not track who is in a team)"),(0,o.kt)("p",null,"An admin needs to go to /admin/settings, click on 'Server', then enter a secret key in the field\n\"GitHub Webhook Secret\", then click the Save button. The secret can be any string you make up.\nRandomly generated strings are encouraged."),(0,o.kt)("p",null,'Next, go to GitGub. In the Repository or Organization that you want to send updates for, go to\nSettings -> Code(, planning,) and automation -> Webhooks, then click "Add webhook".'),(0,o.kt)("p",null,"For Payload URL, enter ",(0,o.kt)("inlineCode",{parentName:"p"},"/github-repo-access-webhook"),", e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"https://api.example.com/github-repo-access-webhook"),"\nSet Content Type to ",(0,o.kt)("inlineCode",{parentName:"p"},"application/json"),'. For Secret, enter the secret from the earlier step. For\n"Which events would you like to trigger this webhook?", select "Let me select individual events."\nIn the list of events that appears, uncheck "Pushes", anf check "Collaborator add, remove, or changed".\nAt the very bottom of the page, click the green button "Add webhook".'),(0,o.kt)("p",null,'After the webhook is created, the webhook will send a ping request to the API endpoint you provided. If the URL\nwas entered correctly, and the secret was entered correctly in both ends, the ping should get a 200 response.\nYou can check the status under the "Recent Deliveries" tab of that webhook on GitHub.'),(0,o.kt)("p",null,"When this is working, whenever a user is added, removed, or has their access modified, the engine\nwill re-fetch the user's full set of GitHub repo accesses and update the database's records."))}c.isMDXComponent=!0},1413:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png"}}]); \ No newline at end of file diff --git a/assets/js/1426.3913c64b.js b/assets/js/1426.3913c64b.js new file mode 100644 index 000000000000..7012afaaf04f --- /dev/null +++ b/assets/js/1426.3913c64b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1426],{1426:(e,t,r)=>{function n(e,t){var r=void 0;return function(){for(var n=arguments.length,o=new Array(n),i=0;ipn});var a=function(){};function c(e){var t=e.item,r=e.items;return{index:t.__autocomplete_indexName,items:[t],positions:[1+r.findIndex((function(e){return e.objectID===t.objectID}))],queryID:t.__autocomplete_queryID,algoliaSource:["autocomplete"]}}function l(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,a,c=[],l=!0,u=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;l=!1}else for(;!(l=(n=i.call(r)).done)&&(c.push(n.value),c.length!==t);l=!0);}catch(s){u=!0,o=s}finally{try{if(!l&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(u)throw o}}return c}}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return u(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return u(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function y(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 h(e){for(var t=1;t=3||2===r&&n>=4||1===r&&n>=10);function i(t,r,n){if(o&&void 0!==n){var i=n[0].__autocomplete_algoliaCredentials,a={"X-Algolia-Application-Id":i.appId,"X-Algolia-API-Key":i.apiKey};e.apply(void 0,[t].concat(p(r),[{headers:a}]))}else e.apply(void 0,[t].concat(p(r)))}return{init:function(t,r){e("init",{appId:t,apiKey:r})},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("clickedObjectIDsAfterSearch",g(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("clickedObjectIDs",g(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n0&&e.apply(void 0,["clickedFilters"].concat(r))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("convertedObjectIDsAfterSearch",g(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("convertedObjectIDs",g(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n0&&e.apply(void 0,["convertedFilters"].concat(r))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&t.reduce((function(e,t){var r=t.items,n=d(t,f);return[].concat(p(e),p(function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,r=[],n=0;n0&&e.apply(void 0,["viewedFilters"].concat(r))}}}function S(e){var t=e.items.reduce((function(e,t){var r;return e[t.__autocomplete_indexName]=(null!==(r=e[t.__autocomplete_indexName])&&void 0!==r?r:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function j(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function w(e){return w="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},w(e)}function E(e){return function(e){if(Array.isArray(e))return P(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return P(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return P(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function P(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r0&&C({onItemsChange:o,items:r,insights:f,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,r=e.onSelect,n=e.onActive;s("addAlgoliaAgent","insights-plugin"),t({algoliaInsightsPlugin:{__algoliaSearchParameters:{clickAnalytics:!0},insights:f}}),r((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&l({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Selected"},c({item:t,items:m.current}))]})})),n((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&u({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Active"},c({item:t,items:m.current}))]})}))},onStateChange:function(e){var t=e.state;p({state:t})},__autocomplete_pluginOptions:e}}function N(e){return N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},N(e)}function T(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 q(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==N(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==N(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===N(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function R(e,t,r){var n,o=t.initialState;return{getState:function(){return o},dispatch:function(n,i){var a=function(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r0},reshape:function(e){return e.sources}},e),{},{id:null!==(r=e.id)&&void 0!==r?r:"autocomplete-".concat(V++),plugins:o,initialState:X({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var r;null===(r=e.onStateChange)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onStateChange)||void 0===r?void 0:r.call(e,t)}))},onSubmit:function(t){var r;null===(r=e.onSubmit)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onSubmit)||void 0===r?void 0:r.call(e,t)}))},onReset:function(t){var r;null===(r=e.onReset)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onReset)||void 0===r?void 0:r.call(e,t)}))},getSources:function(r){return Promise.all([].concat(Q(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var r=[];return Promise.resolve(e(t)).then((function(e){return Array.isArray(e),Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,r.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));r.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:a,onResolve:a};Object.keys(t).forEach((function(e){t[e].__default=!0}));var n=$($({},t),e);return Promise.resolve(n)})))}))}(e,r)}))).then((function(e){return L(e)})).then((function(e){return e.map((function(e){return X(X({},e),{},{onSelect:function(r){e.onSelect(r),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,r)}))},onActive:function(r){e.onActive(r),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,r)}))},onResolve:function(r){e.onResolve(r),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,r)}))}})}))}))},navigator:X({navigate:function(e){var t=e.itemUrl;n.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,r=n.open(t,"_blank","noopener");null==r||r.focus()},navigateNewWindow:function(e){var t=e.itemUrl;n.open(t,"_blank","noopener")}},e.navigator)})}function te(e){return te="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},te(e)}function re(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 ne(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Ie,De,Ae,ke=null,xe=(Ie=-1,De=-1,Ae=void 0,function(e){var t=++Ie;return Promise.resolve(e).then((function(e){return Ae&&t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Me=/((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i;function He(e){return He="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},He(e)}var Fe=["props","refresh","store"],Ue=["inputElement","formElement","panelElement"],Be=["inputElement"],Ve=["inputElement","maxLength"],Ke=["sourceIndex"],$e=["sourceIndex"],Je=["item","source","sourceIndex"];function ze(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 We(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ge(e){var t=e.props,r=e.refresh,n=e.store,o=Ze(e,Fe),i=function(e,t){return void 0!==t?"".concat(e,"-").concat(t):e};return{getEnvironmentProps:function(e){var r=e.inputElement,o=e.formElement,i=e.panelElement;function a(e){!n.getState().isOpen&&n.pendingRequests.isEmpty()||e.target===r||!1===[o,i].some((function(t){return r=t,n=e.target,r===n||r.contains(n);var r,n}))&&(n.dispatch("blur",null),t.debug||n.pendingRequests.cancelAll())}return We({onTouchStart:a,onMouseDown:a,onTouchMove:function(e){!1!==n.getState().isOpen&&r===t.environment.document.activeElement&&e.target!==r&&r.blur()}},Ze(e,Ue))},getRootProps:function(e){return We({role:"combobox","aria-expanded":n.getState().isOpen,"aria-haspopup":"listbox","aria-owns":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){e.inputElement;return We({action:"",noValidate:!0,role:"search",onSubmit:function(i){var a;i.preventDefault(),t.onSubmit(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("submit",null),null===(a=e.inputElement)||void 0===a||a.blur()},onReset:function(i){var a;i.preventDefault(),t.onReset(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("reset",null),null===(a=e.inputElement)||void 0===a||a.focus()}},Ze(e,Be))},getLabelProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,Ke);return We({htmlFor:"".concat(i(t.id,n),"-input"),id:"".concat(i(t.id,n),"-label")},o)},getInputProps:function(e){var i;function c(e){(t.openOnFocus||Boolean(n.getState().query))&&Ce(We({event:e,props:t,query:n.getState().completion||n.getState().query,refresh:r,store:n},o)),n.dispatch("focus",null)}var l=e||{},u=(l.inputElement,l.maxLength),s=void 0===u?512:u,f=Ze(l,Ve),m=ge(n.getState()),p=function(e){return Boolean(e&&e.match(Me))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),v=null!=m&&m.itemUrl&&!p?"go":"search";return We({"aria-autocomplete":"both","aria-activedescendant":n.getState().isOpen&&null!==n.getState().activeItemId?"".concat(t.id,"-item-").concat(n.getState().activeItemId):void 0,"aria-controls":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:n.getState().completion||n.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:v,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:s,type:"search",onChange:function(e){Ce(We({event:e,props:t,query:e.currentTarget.value.slice(0,s),refresh:r,store:n},o))},onKeyDown:function(e){!function(e){var t=e.event,r=e.props,n=e.refresh,o=e.store,i=Le(e,Ne);if("ArrowUp"===t.key||"ArrowDown"===t.key){var a=function(){var e=r.environment.document.getElementById("".concat(r.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},c=function(){var e=ge(o.getState());if(null!==o.getState().activeItemId&&e){var r=e.item,a=e.itemInputValue,c=e.itemUrl,l=e.source;l.onActive(qe({event:t,item:r,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(r.openOnFocus||Boolean(o.getState().query))?Ce(qe({event:t,props:r,query:o.getState().query,refresh:n,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:r.defaultActiveItemId}),c(),setTimeout(a,0)})):(o.dispatch(t.key,{}),c(),a())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(r.debug||o.pendingRequests.cancelAll());t.preventDefault();var l=ge(o.getState()),u=l.item,s=l.itemInputValue,f=l.itemUrl,m=l.source;if(t.metaKey||t.ctrlKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewTab({itemUrl:f,item:u,state:o.getState()}));else if(t.shiftKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewWindow({itemUrl:f,item:u,state:o.getState()}));else if(t.altKey);else{if(void 0!==f)return m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),void r.navigator.navigate({itemUrl:f,item:u,state:o.getState()});Ce(qe({event:t,nextState:{isOpen:!1},props:r,query:s,refresh:n,store:o},i)).then((function(){m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i))}))}}}(We({event:e,props:t,refresh:r,store:n},o))},onFocus:c,onBlur:a,onClick:function(r){e.inputElement!==t.environment.document.activeElement||n.getState().isOpen||c(r)}},f)},getPanelProps:function(e){return We({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){n.dispatch("mouseleave",null)}},e)},getListProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,$e);return We({role:"listbox","aria-labelledby":"".concat(i(t.id,n),"-label"),id:"".concat(i(t.id,n),"-list")},o)},getItemProps:function(e){var a=e.item,c=e.source,l=e.sourceIndex,u=Ze(e,Je);return We({id:"".concat(i(t.id,l),"-item-").concat(a.__autocomplete_id),role:"option","aria-selected":n.getState().activeItemId===a.__autocomplete_id,onMouseMove:function(e){if(a.__autocomplete_id!==n.getState().activeItemId){n.dispatch("mousemove",a.__autocomplete_id);var t=ge(n.getState());if(null!==n.getState().activeItemId&&t){var i=t.item,c=t.itemInputValue,l=t.itemUrl,u=t.source;u.onActive(We({event:e,item:i,itemInputValue:c,itemUrl:l,refresh:r,source:u,state:n.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var i=c.getItemInputValue({item:a,state:n.getState()}),l=c.getItemUrl({item:a,state:n.getState()});(l?Promise.resolve():Ce(We({event:e,nextState:{isOpen:!1},props:t,query:i,refresh:r,store:n},o))).then((function(){c.onSelect(We({event:e,item:a,itemInputValue:i,itemUrl:l,refresh:r,source:c,state:n.getState()},o))}))}},u)}}}var Xe=[{segment:"autocomplete-core",version:"1.9.3"}];function Ye(e){return Ye="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ye(e)}function et(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 tt(e){for(var t=1;t=r?null===n?null:0:o}function at(e){return at="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},at(e)}function ct(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 lt(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function kt(e){var t=e.translations,r=void 0===t?{}:t,n=At(e,Pt),o=r.noResultsText,i=void 0===o?"No results for":o,a=r.suggestedQueryText,c=void 0===a?"Try searching for":a,l=r.reportMissingResultsText,u=void 0===l?"Believe this query should return results?":l,s=r.reportMissingResultsLinkText,f=void 0===s?"Let us know.":s,m=n.state.context.searchSuggestions;return yt.createElement("div",{className:"DocSearch-NoResults"},yt.createElement("div",{className:"DocSearch-Screen-Icon"},yt.createElement(Et,null)),yt.createElement("p",{className:"DocSearch-Title"},i,' "',yt.createElement("strong",null,n.state.query),'"'),m&&m.length>0&&yt.createElement("div",{className:"DocSearch-NoResults-Prefill-List"},yt.createElement("p",{className:"DocSearch-Help"},c,":"),yt.createElement("ul",null,m.slice(0,3).reduce((function(e,t){return[].concat(It(e),[yt.createElement("li",{key:t},yt.createElement("button",{className:"DocSearch-Prefill",key:t,type:"button",onClick:function(){n.setQuery(t.toLowerCase()+" "),n.refresh(),n.inputRef.current.focus()}},t))])}),[]))),n.getMissingResultsUrl&&yt.createElement("p",{className:"DocSearch-Help"},"".concat(u," "),yt.createElement("a",{href:n.getMissingResultsUrl({query:n.state.query}),target:"_blank",rel:"noopener noreferrer"},f)))}var xt=function(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))};function Ct(e){switch(e.type){case"lvl1":return yt.createElement(xt,null);case"content":return yt.createElement(Nt,null);default:return yt.createElement(_t,null)}}function _t(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}function Nt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 5H3h14zm0 5H3h14zm0 5H3h14z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function Tt(){return yt.createElement("svg",{className:"DocSearch-Hit-Select-Icon",width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M18 3v4c0 2-2 4-4 4H2"}),yt.createElement("path",{d:"M8 17l-6-6 6-6"})))}var qt=["hit","attribute","tagName"];function Rt(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 Lt(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ft(e,t){return t.split(".").reduce((function(e,t){return null!=e&&e[t]?e[t]:null}),e)}function Ut(e){var t=e.hit,r=e.attribute,n=e.tagName,o=void 0===n?"span":n,i=Ht(e,qt);return(0,yt.createElement)(o,Lt(Lt({},i),{},{dangerouslySetInnerHTML:{__html:Ft(t,"_snippetResult.".concat(r,".value"))||Ft(t,r)}}))}function Bt(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==r)return;var n,o,i=[],a=!0,c=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(l){c=!0,o=l}finally{try{a||null==r.return||r.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Vt(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Vt(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vt(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r|<\/mark>)/g,Wt=RegExp(zt.source);function Qt(e){var t,r,n=e;if(!n.__docsearch_parent&&!e._highlightResult)return e.hierarchy.lvl0;var o=((n.__docsearch_parent?null===(t=n.__docsearch_parent)||void 0===t||null===(t=t._highlightResult)||void 0===t||null===(t=t.hierarchy)||void 0===t?void 0:t.lvl0:null===(r=e._highlightResult)||void 0===r||null===(r=r.hierarchy)||void 0===r?void 0:r.lvl0)||{}).value;return o&&Wt.test(o)?o.replace(zt,""):o}function Zt(){return Zt=Object.assign||function(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function or(e){var t=e.translations,r=void 0===t?{}:t,n=nr(e,tr),o=r.recentSearchesTitle,i=void 0===o?"Recent":o,a=r.noRecentSearchesText,c=void 0===a?"No recent searches":a,l=r.saveRecentSearchButtonTitle,u=void 0===l?"Save this search":l,s=r.removeRecentSearchButtonTitle,f=void 0===s?"Remove this search from history":s,m=r.favoriteSearchesTitle,p=void 0===m?"Favorite":m,v=r.removeFavoriteSearchButtonTitle,d=void 0===v?"Remove this search from favorites":v;return"idle"===n.state.status&&!1===n.hasCollections?n.disableUserPersonalization?null:yt.createElement("div",{className:"DocSearch-StartScreen"},yt.createElement("p",{className:"DocSearch-Help"},c)):!1===n.hasCollections?null:yt.createElement("div",{className:"DocSearch-Dropdown-Container"},yt.createElement($t,rr({},n,{title:i,collection:n.state.collections[0],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Xt,null))},renderAction:function(e){var t=e.item,r=e.runFavoriteTransition,o=e.runDeleteTransition;return yt.createElement(yt.Fragment,null,yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:u,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.add(t),n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(Yt,null))),yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:f,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),o((function(){n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(er,null))))}})),yt.createElement($t,rr({},n,{title:p,collection:n.state.collections[1],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Yt,null))},renderAction:function(e){var t=e.item,r=e.runDeleteTransition;return yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:d,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.remove(t),n.refresh()}))}},yt.createElement(er,null)))}})))}var ir=["translations"];function ar(){return ar=Object.assign||function(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var lr=yt.memo((function(e){var t=e.translations,r=void 0===t?{}:t,n=cr(e,ir);if("error"===n.state.status)return yt.createElement(wt,{translations:null==r?void 0:r.errorScreen});var o=n.state.collections.some((function(e){return e.items.length>0}));return n.state.query?!1===o?yt.createElement(kt,ar({},n,{translations:null==r?void 0:r.noResultsScreen})):yt.createElement(Gt,n):yt.createElement(or,ar({},n,{hasCollections:o,translations:null==r?void 0:r.startScreen}))}),(function(e,t){return"loading"===t.state.status||"stalled"===t.state.status}));function ur(){return yt.createElement("svg",{viewBox:"0 0 38 38",stroke:"currentColor",strokeOpacity:".5"},yt.createElement("g",{fill:"none",fillRule:"evenodd"},yt.createElement("g",{transform:"translate(1 1)",strokeWidth:"2"},yt.createElement("circle",{strokeOpacity:".3",cx:"18",cy:"18",r:"18"}),yt.createElement("path",{d:"M36 18c0-9.94-8.06-18-18-18"},yt.createElement("animateTransform",{attributeName:"transform",type:"rotate",from:"0 18 18",to:"360 18 18",dur:"1s",repeatCount:"indefinite"})))))}var sr=r(830),fr=["translations"];function mr(){return mr=Object.assign||function(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function vr(e){var t=e.translations,r=void 0===t?{}:t,n=pr(e,fr),o=r.resetButtonTitle,i=void 0===o?"Clear the query":o,a=r.resetButtonAriaLabel,c=void 0===a?"Clear the query":a,l=r.cancelButtonText,u=void 0===l?"Cancel":l,s=r.cancelButtonAriaLabel,f=void 0===s?"Cancel":s,m=n.getFormProps({inputElement:n.inputRef.current}).onReset;return yt.useEffect((function(){n.autoFocus&&n.inputRef.current&&n.inputRef.current.focus()}),[n.autoFocus,n.inputRef]),yt.useEffect((function(){n.isFromSelection&&n.inputRef.current&&n.inputRef.current.select()}),[n.isFromSelection,n.inputRef]),yt.createElement(yt.Fragment,null,yt.createElement("form",{className:"DocSearch-Form",onSubmit:function(e){e.preventDefault()},onReset:m},yt.createElement("label",mr({className:"DocSearch-MagnifierLabel"},n.getLabelProps()),yt.createElement(sr.W,null)),yt.createElement("div",{className:"DocSearch-LoadingIndicator"},yt.createElement(ur,null)),yt.createElement("input",mr({className:"DocSearch-Input",ref:n.inputRef},n.getInputProps({inputElement:n.inputRef.current,autoFocus:n.autoFocus,maxLength:ht}))),yt.createElement("button",{type:"reset",title:i,className:"DocSearch-Reset","aria-label":c,hidden:!n.state.query},yt.createElement(er,null))),yt.createElement("button",{className:"DocSearch-Cancel",type:"reset","aria-label":f,onClick:n.onClose},u))}var dr=["_highlightResult","_snippetResult"];function yr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function hr(e){return!1===function(){var e="__TEST_KEY__";try{return localStorage.setItem(e,""),localStorage.removeItem(e),!0}catch(t){return!1}}()?{setItem:function(){},getItem:function(){return[]}}:{setItem:function(t){return window.localStorage.setItem(e,JSON.stringify(t))},getItem:function(){var t=window.localStorage.getItem(e);return t?JSON.parse(t):[]}}}function br(e){var t=e.key,r=e.limit,n=void 0===r?5:r,o=hr(t),i=o.getItem().slice(0,n);return{add:function(e){var t=e,r=(t._highlightResult,t._snippetResult,yr(t,dr)),a=i.findIndex((function(e){return e.objectID===r.objectID}));a>-1&&i.splice(a,1),i.unshift(r),i=i.slice(0,n),o.setItem(i)},remove:function(e){i=i.filter((function(t){return t.objectID!==e.objectID})),o.setItem(i)},getAll:function(){return i}}}function gr(e){const t=`algoliasearch-client-js-${e.key}`;let r;const n=()=>(void 0===r&&(r=e.localStorage||window.localStorage),r),o=()=>JSON.parse(n().getItem(t)||"{}"),i=e=>{n().setItem(t,JSON.stringify(e))};return{get:(t,r,n={miss:()=>Promise.resolve()})=>Promise.resolve().then((()=>{(()=>{const t=e.timeToLive?1e3*e.timeToLive:null,r=o(),n=Object.fromEntries(Object.entries(r).filter((([,e])=>void 0!==e.timestamp)));if(i(n),!t)return;const a=Object.fromEntries(Object.entries(n).filter((([,e])=>{const r=(new Date).getTime();return!(e.timestamp+tPromise.all([e?e.value:r(),void 0!==e]))).then((([e,t])=>Promise.all([e,t||n.miss(e)]))).then((([e])=>e)),set:(e,r)=>Promise.resolve().then((()=>{const i=o();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:r},n().setItem(t,JSON.stringify(i)),r})),delete:e=>Promise.resolve().then((()=>{const r=o();delete r[JSON.stringify(e)],n().setItem(t,JSON.stringify(r))})),clear:()=>Promise.resolve().then((()=>{n().removeItem(t)}))}}function Or(e){const t=[...e.caches],r=t.shift();return void 0===r?{get:(e,t,r={miss:()=>Promise.resolve()})=>t().then((e=>Promise.all([e,r.miss(e)]))).then((([e])=>e)),set:(e,t)=>Promise.resolve(t),delete:e=>Promise.resolve(),clear:()=>Promise.resolve()}:{get:(e,n,o={miss:()=>Promise.resolve()})=>r.get(e,n,o).catch((()=>Or({caches:t}).get(e,n,o))),set:(e,n)=>r.set(e,n).catch((()=>Or({caches:t}).set(e,n))),delete:e=>r.delete(e).catch((()=>Or({caches:t}).delete(e))),clear:()=>r.clear().catch((()=>Or({caches:t}).clear()))}}function Sr(e={serializable:!0}){let t={};return{get(r,n,o={miss:()=>Promise.resolve()}){const i=JSON.stringify(r);if(i in t)return Promise.resolve(e.serializable?JSON.parse(t[i]):t[i]);const a=n(),c=o&&o.miss||(()=>Promise.resolve());return a.then((e=>c(e))).then((()=>a))},set:(r,n)=>(t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)),delete:e=>(delete t[JSON.stringify(e)],Promise.resolve()),clear:()=>(t={},Promise.resolve())}}function jr(e){let t=e.length-1;for(;t>0;t--){const r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function wr(e,t){return t?(Object.keys(t).forEach((r=>{e[r]=t[r](e)})),e):e}function Er(e,...t){let r=0;return e.replace(/%s/g,(()=>encodeURIComponent(t[r++])))}const Pr="4.20.0",Ir={WithinQueryParameters:0,WithinHeaders:1};function Dr(e,t){const r=e||{},n=r.data||{};return Object.keys(r).forEach((e=>{-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}const Ar={Read:1,Write:2,Any:3},kr={Up:1,Down:2,Timeouted:3},xr=12e4;function Cr(e,t=kr.Up){return{...e,status:t,lastUpdate:Date.now()}}function _r(e){return"string"==typeof e?{protocol:"https",url:e,accept:Ar.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||Ar.Any}}const Nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};function Tr(e,t){return Promise.all(t.map((t=>e.get(t,(()=>Promise.resolve(Cr(t))))))).then((e=>{const r=e.filter((e=>function(e){return e.status===kr.Up||Date.now()-e.lastUpdate>xr}(e))),n=e.filter((e=>function(e){return e.status===kr.Timeouted&&Date.now()-e.lastUpdate<=xr}(e))),o=[...r,...n];return{getTimeout:(e,t)=>(0===n.length&&0===e?1:n.length+3+e)*t,statelessHosts:o.length>0?o.map((e=>_r(e))):t}}))}const qr=(e,t)=>(e=>{const t=e.status;return e.isTimedOut||(({isTimedOut:e,status:t})=>!e&&0==~~t)(e)||2!=~~(t/100)&&4!=~~(t/100)})(e)?t.onRetry(e):(({status:e})=>2==~~(e/100))(e)?t.onSuccess(e):t.onFail(e);function Rr(e,t,r,n){const o=[],i=function(e,t){if(e.method===Nr.Get||void 0===e.data&&void 0===t.data)return;const r=Array.isArray(e.data)?e.data:{...e.data,...t.data};return JSON.stringify(r)}(r,n),a=function(e,t){const r={...e.headers,...t.headers},n={};return Object.keys(r).forEach((e=>{const t=r[e];n[e.toLowerCase()]=t})),n}(e,n),c=r.method,l=r.method!==Nr.Get?{}:{...r.data,...n.data},u={"x-algolia-agent":e.userAgent.value,...e.queryParameters,...l,...n.queryParameters};let s=0;const f=(t,l)=>{const m=t.pop();if(void 0===m)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:Fr(o)};const p={data:i,headers:a,method:c,url:Mr(m,r.path,u),connectTimeout:l(s,e.timeouts.connect),responseTimeout:l(s,n.timeout)},v=e=>{const r={request:p,response:e,host:m,triesLeft:t.length};return o.push(r),r},d={onSuccess:e=>function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e),onRetry(r){const n=v(r);return r.isTimedOut&&s++,Promise.all([e.logger.info("Retryable failure",Ur(n)),e.hostsCache.set(m,Cr(m,r.isTimedOut?kr.Timeouted:kr.Down))]).then((()=>f(t,l)))},onFail(e){throw v(e),function({content:e,status:t},r){let n=e;try{n=JSON.parse(e).message}catch(o){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(n,t,r)}(e,Fr(o))}};return e.requester.send(p).then((e=>qr(e,d)))};return Tr(e.hostsCache,t).then((e=>f([...e.statelessHosts].reverse(),e.getTimeout)))}function Lr(e){const t={value:`Algolia for JavaScript (${e})`,add(e){const r=`; ${e.segment}${void 0!==e.version?` (${e.version})`:""}`;return-1===t.value.indexOf(r)&&(t.value=`${t.value}${r}`),t}};return t}function Mr(e,t,r){const n=Hr(r);let o=`${e.protocol}://${e.url}/${"/"===t.charAt(0)?t.substr(1):t}`;return n.length&&(o+=`?${n}`),o}function Hr(e){return Object.keys(e).map((t=>{return Er("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function Fr(e){return e.map((e=>Ur(e)))}function Ur(e){const t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...e,request:{...e.request,headers:{...e.request.headers,...t}}}}const Br=e=>{const t=e.appId,r=function(e,t,r){const n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:()=>e===Ir.WithinHeaders?n:{},queryParameters:()=>e===Ir.WithinQueryParameters?n:{}}}(void 0!==e.authMode?e.authMode:Ir.WithinHeaders,t,e.apiKey),n=function(e){const{hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,hosts:l,queryParameters:u,headers:s}=e,f={hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,headers:s,queryParameters:u,hosts:l.map((e=>_r(e))),read(e,t){const r=Dr(t,f.timeouts.read),n=()=>Rr(f,f.hosts.filter((e=>0!=(e.accept&Ar.Read))),e,r);if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();const o={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(o,(()=>f.requestsCache.get(o,(()=>f.requestsCache.set(o,n()).then((e=>Promise.all([f.requestsCache.delete(o),e])),(e=>Promise.all([f.requestsCache.delete(o),Promise.reject(e)]))).then((([e,t])=>t))))),{miss:e=>f.responsesCache.set(o,e)})},write:(e,t)=>Rr(f,f.hosts.filter((e=>0!=(e.accept&Ar.Write))),e,Dr(t,f.timeouts.write))};return f}({hosts:[{url:`${t}-dsn.algolia.net`,accept:Ar.Read},{url:`${t}.algolia.net`,accept:Ar.Write}].concat(jr([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}])),...e,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...e.headers},queryParameters:{...r.queryParameters(),...e.queryParameters}}),o={transporter:n,appId:t,addAlgoliaAgent(e,t){n.userAgent.add({segment:e,version:t})},clearCache:()=>Promise.all([n.requestsCache.clear(),n.responsesCache.clear()]).then((()=>{}))};return wr(o,e.methods)},Vr=e=>(t,r)=>t.method===Nr.Get?e.transporter.read(t,r):e.transporter.write(t,r),Kr=e=>(t,r={})=>wr({transporter:e.transporter,appId:e.appId,indexName:t},r.methods),$r=e=>(t,r)=>{const n=t.map((e=>({...e,params:Hr(e.params||{})})));return e.transporter.read({method:Nr.Post,path:"1/indexes/*/queries",data:{requests:n},cacheable:!0},r)},Jr=e=>(t,r)=>Promise.all(t.map((t=>{const{facetName:n,facetQuery:o,...i}=t.params;return Kr(e)(t.indexName,{methods:{searchForFacetValues:Qr}}).searchForFacetValues(n,o,{...r,...i})}))),zr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n),Wr=e=>(t,r)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),Qr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n),Zr={Debug:1,Info:2,Error:3};function Gr(e,t,r){const n={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:e=>new Promise((t=>{const r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((t=>r.setRequestHeader(t,e.headers[t])));const n=(e,n)=>setTimeout((()=>{r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e),o=n(e.connectTimeout,"Connection timeout");let i;r.onreadystatechange=()=>{r.readyState>r.OPENED&&void 0===i&&(clearTimeout(o),i=n(e.responseTimeout,"Socket timeout"))},r.onerror=()=>{0===r.status&&(clearTimeout(o),clearTimeout(i),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=()=>{clearTimeout(o),clearTimeout(i),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))},logger:(o=Zr.Error,{debug:(e,t)=>(Zr.Debug>=o&&console.debug(e,t),Promise.resolve()),info:(e,t)=>(Zr.Info>=o&&console.info(e,t),Promise.resolve()),error:(e,t)=>(console.error(e,t),Promise.resolve())}),responsesCache:Sr(),requestsCache:Sr({serializable:!1}),hostsCache:Or({caches:[gr({key:`${Pr}-${e}`}),Sr()]}),userAgent:Lr(Pr).add({segment:"Browser",version:"lite"}),authMode:Ir.WithinQueryParameters};var o;return Br({...n,...r,methods:{search:$r,searchForFacetValues:Jr,multipleQueries:$r,multipleSearchForFacetValues:Jr,customRequest:Vr,initIndex:e=>t=>Kr(e)(t,{methods:{search:Wr,searchForFacetValues:Qr,findAnswers:zr}})}})}Gr.version=Pr;const Xr=Gr;var Yr="3.5.2";function en(){}function tn(e){return e}function rn(e){return 1===e.button||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey}function nn(e,t,r){return e.reduce((function(e,n){var o=t(n);return e.hasOwnProperty(o)||(e[o]=[]),e[o].length<(r||5)&&e[o].push(n),e}),{})}var on=["footer","searchBox"];function an(){return an=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function pn(e){var t=e.appId,r=e.apiKey,n=e.indexName,o=e.placeholder,i=void 0===o?"Search docs":o,a=e.searchParameters,c=e.maxResultsPerGroup,l=e.onClose,u=void 0===l?en:l,s=e.transformItems,f=void 0===s?tn:s,m=e.hitComponent,p=void 0===m?St:m,v=e.resultsFooterComponent,d=void 0===v?function(){return null}:v,y=e.navigator,h=e.initialScrollY,b=void 0===h?0:h,g=e.transformSearchClient,O=void 0===g?tn:g,S=e.disableUserPersonalization,j=void 0!==S&&S,w=e.initialQuery,E=void 0===w?"":w,P=e.translations,I=void 0===P?{}:P,D=e.getMissingResultsUrl,A=e.insights,k=void 0!==A&&A,x=I.footer,C=I.searchBox,_=mn(I,on),N=sn(yt.useState({query:"",collections:[],completion:null,context:{},isOpen:!1,activeItemId:null,status:"idle"}),2),T=N[0],q=N[1],R=yt.useRef(null),L=yt.useRef(null),M=yt.useRef(null),H=yt.useRef(null),F=yt.useRef(null),U=yt.useRef(10),B=yt.useRef("undefined"!=typeof window?window.getSelection().toString().slice(0,ht):"").current,V=yt.useRef(E||B).current,K=function(e,t,r){return yt.useMemo((function(){var n=Xr(e,t);return n.addAlgoliaAgent("docsearch",Yr),!1===/docsearch.js \(.*\)/.test(n.transporter.userAgent.value)&&n.addAlgoliaAgent("docsearch-react",Yr),r(n)}),[e,t,r])}(t,r,O),$=yt.useRef(br({key:"__DOCSEARCH_FAVORITE_SEARCHES__".concat(n),limit:10})).current,J=yt.useRef(br({key:"__DOCSEARCH_RECENT_SEARCHES__".concat(n),limit:0===$.getAll().length?7:4})).current,z=yt.useCallback((function(e){if(!j){var t="content"===e.type?e.__docsearch_parent:e;t&&-1===$.getAll().findIndex((function(e){return e.objectID===t.objectID}))&&J.add(t)}}),[$,J,j]),W=yt.useCallback((function(e){if(T.context.algoliaInsightsPlugin&&e.__autocomplete_id){var t=e,r={eventName:"Item Selected",index:t.__autocomplete_indexName,items:[t],positions:[e.__autocomplete_id],queryID:t.__autocomplete_queryID};T.context.algoliaInsightsPlugin.insights.clickedObjectIDsAfterSearch(r)}}),[T.context.algoliaInsightsPlugin]),Q=yt.useMemo((function(){return dt({id:"docsearch",defaultActiveItemId:0,placeholder:i,openOnFocus:!0,initialState:{query:V,context:{searchSuggestions:[]}},insights:k,navigator:y,onStateChange:function(e){q(e.state)},getSources:function(e){var o=e.query,i=e.state,l=e.setContext,s=e.setStatus;if(!o)return j?[]:[{sourceId:"recentSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return J.getAll()}},{sourceId:"favoriteSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return $.getAll()}}];var m=Boolean(k);return K.search([{query:o,indexName:n,params:ln({attributesToRetrieve:["hierarchy.lvl0","hierarchy.lvl1","hierarchy.lvl2","hierarchy.lvl3","hierarchy.lvl4","hierarchy.lvl5","hierarchy.lvl6","content","type","url"],attributesToSnippet:["hierarchy.lvl1:".concat(U.current),"hierarchy.lvl2:".concat(U.current),"hierarchy.lvl3:".concat(U.current),"hierarchy.lvl4:".concat(U.current),"hierarchy.lvl5:".concat(U.current),"hierarchy.lvl6:".concat(U.current),"content:".concat(U.current)],snippetEllipsisText:"\u2026",highlightPreTag:"",highlightPostTag:"",hitsPerPage:20,clickAnalytics:m},a)}]).catch((function(e){throw"RetryError"===e.name&&s("error"),e})).then((function(e){var o=e.results[0],a=o.hits,s=o.nbHits,p=nn(a,(function(e){return Qt(e)}),c);i.context.searchSuggestions.length0&&(X(),F.current&&F.current.focus())}),[V,X]),yt.useEffect((function(){function e(){if(L.current){var e=.01*window.innerHeight;L.current.style.setProperty("--docsearch-vh","".concat(e,"px"))}}return e(),window.addEventListener("resize",e),function(){window.removeEventListener("resize",e)}}),[]),yt.createElement("div",an({ref:R},G({"aria-expanded":!0}),{className:["DocSearch","DocSearch-Container","stalled"===T.status&&"DocSearch-Container--Stalled","error"===T.status&&"DocSearch-Container--Errored"].filter(Boolean).join(" "),role:"button",tabIndex:0,onMouseDown:function(e){e.target===e.currentTarget&&u()}}),yt.createElement("div",{className:"DocSearch-Modal",ref:L},yt.createElement("header",{className:"DocSearch-SearchBar",ref:M},yt.createElement(vr,an({},Q,{state:T,autoFocus:0===V.length,inputRef:F,isFromSelection:Boolean(V)&&V===B,translations:C,onClose:u}))),yt.createElement("div",{className:"DocSearch-Dropdown",ref:H},yt.createElement(lr,an({},Q,{indexName:n,state:T,hitComponent:p,resultsFooterComponent:d,disableUserPersonalization:j,recentSearches:J,favoriteSearches:$,inputRef:F,translations:_,getMissingResultsUrl:D,onItemClick:function(e,t){W(e),z(e),rn(t)||u()}}))),yt.createElement("footer",{className:"DocSearch-Footer"},yt.createElement(Ot,{translations:x}))))}}}]); \ No newline at end of file diff --git a/assets/js/14d2cd64.abc81f39.js b/assets/js/14d2cd64.abc81f39.js new file mode 100644 index 000000000000..6264f0e9d498 --- /dev/null +++ b/assets/js/14d2cd64.abc81f39.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2901],{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 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 s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="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,o=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,h=u["".concat(i,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(h,s(s({ref:t},p),{},{components:n})):a.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:r,s[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={},s="State Management",l={unversionedId:"creator/development/state_management",id:"creator/development/state_management",title:"State Management",description:"All of Ethereal Engine's state management uses hookstate and react. Together, these tools give reactive, declarative, and controlled state management across any scope.",source:"@site/docs/2_creator/4_development/1_state_management.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/state_management",permalink:"/etherealengine-docs/docs/creator/development/state_management",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/1_state_management.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Projects",permalink:"/etherealengine-docs/docs/creator/development/projects_overview"},next:{title:"Entities, Components and Systems",permalink:"/etherealengine-docs/docs/creator/development/ecs"}},i={},c=[{value:"Scoped State",id:"scoped-state",level:2},{value:"Global State",id:"global-state",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"state-management"},"State Management"),(0,r.kt)("p",null,"All of Ethereal Engine's state management uses ",(0,r.kt)("a",{parentName:"p",href:"https://hookstate.js.org/"},"hookstate")," and ",(0,r.kt)("a",{parentName:"p",href:"https://react.dev/"},"react"),". Together, these tools give reactive, declarative, and controlled state management across any scope."),(0,r.kt)("h2",{id:"scoped-state"},"Scoped State"),(0,r.kt)("p",null,"Scoped state can be defined using the ",(0,r.kt)("inlineCode",{parentName:"p"},"useHookstate")," hook - this is vanilla hookstate, and is useful for state that is only used in a single component, or state that is only used in a single component tree."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-tsx"},"import { useHookstate } from '@hookstate/core'\n\nconst MyComponent = () => {\n const state = useHookstate({\n count: 0\n })\n return (\n
\n

Count: {state.count}

\n \n
\n )\n}\n")),(0,r.kt)("h2",{id:"global-state"},"Global State"),(0,r.kt)("p",null,"Global state definitions are wrapped in a 'store' which allows for automatic creation and cleanup as needed. This API as well as the underlying hookstate API can be imported from ",(0,r.kt)("inlineCode",{parentName:"p"},"@etherealengine/hyperflux"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="MyState.ts"',title:'"MyState.ts"'},"import { defineState } from '@etherealengine/hyperflux'\n\nconst MyState = defineState({\n name: 'MyState',\n initial: {\n count: 0\n }\n})\n")),(0,r.kt)("p",null,"Global state will be registered to the engine instance once it has been called with ",(0,r.kt)("inlineCode",{parentName:"p"},"getState")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"getMutableState"),". This will cause the state to be created if it does not exist, and will be cleaned up when the engine instance is destroyed."),(0,r.kt)("p",null,"It's proxy can be accessed with ",(0,r.kt)("inlineCode",{parentName:"p"},"Engine.instance.store.stateMap.MyState")," where ",(0,r.kt)("inlineCode",{parentName:"p"},"MyState")," is the name of the state."),(0,r.kt)("p",null,"When accessing the state, ",(0,r.kt)("inlineCode",{parentName:"p"},"getState")," returns the underlying object typed as readonly. This is useful for reading state values, but should not be used to write to state."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"import { getState } from '@etherealengine/hyperflux'\nimport { MyState } from './MyState'\n\nconst state = getState(MyState)\nconsole.log(state.count) // 0\nstate.count = 1 // Error: Cannot assign to 'count' because it is a read-only property.\n")),(0,r.kt)("p",null,"State can be mutated via the ",(0,r.kt)("inlineCode",{parentName:"p"},"getMutableState")," function, which returns a proxy to the state, which can be used to read and write state values. The proxy is reactive, so any changes to the state will cause the component to re-render."),(0,r.kt)("p",null,"The proxy returned can be wrapped in hookstate's reactive hook ",(0,r.kt)("inlineCode",{parentName:"p"},"useHookstate"),". This will cause the component to re-render when any state values are changed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-tsx"},"import { getMutableState, useHookstate } from '@etherealengine/hyperflux'\nimport { MyState } from './MyState'\n\nconst MyComponent = () => {\n const state = useHookstate(getMutableState(MyState))\n return (\n
\n

Count: {state.count}

\n \n
\n )\n}\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/15dae980.a0d880ae.js b/assets/js/15dae980.a0d880ae.js new file mode 100644 index 000000000000..fe61914536df --- /dev/null +++ b/assets/js/15dae980.a0d880ae.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1489],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>h});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},p=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),d=u(t),m=i,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||l;return t?a.createElement(h,o(o({ref:n},p),{},{components:t})):a.createElement(h,o({ref:n},p))}));function h(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var l=t.length,o=new Array(l);o[0]=m;var r={};for(var s in n)hasOwnProperty.call(n,s)&&(r[s]=n[s]);r.originalType=e,r[d]="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={},o="Installing on Windows with WSL2",r={unversionedId:"host/installation/windows_wsl",id:"host/installation/windows_wsl",title:"Installing on Windows with WSL2",description:"This guide is currently tested on Windows 10 (22H2) and Windows 11.",source:"@site/docs/1_host/1_installation/3_windows_wsl.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/windows_wsl",permalink:"/etherealengine-docs/docs/host/installation/windows_wsl",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/3_windows_wsl.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing on Windows 10+",permalink:"/etherealengine-docs/docs/host/installation/windows"},next:{title:"Advanced Setup",permalink:"/etherealengine-docs/docs/host/installation/advanced_setup"}},s={},u=[{value:"Install Windows Subsystem for Linux (WSL).",id:"install-windows-subsystem-for-linux-wsl",level:2},{value:"Install Docker Desktop",id:"install-docker-desktop",level:2},{value:"Install Node.",id:"install-node",level:2},{value:"Install Python 3",id:"install-python-3",level:2},{value:"Install Make",id:"install-make",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Initialize MariaDB server",id:"initialize-mariadb-server",level:2},{value:"Start Engine Stack",id:"start-engine-stack",level:2},{value:"Accept Certificates",id:"accept-certificates",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...l}=e;return(0,i.kt)(d,(0,a.Z)({},p,l,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"installing-on-windows-with-wsl2"},"Installing on Windows with WSL2"),(0,i.kt)("p",null,"This guide is currently tested on Windows 10 (22H2) and Windows 11."),(0,i.kt)("h2",{id:"install-windows-subsystem-for-linux-wsl"},"Install Windows Subsystem for Linux (WSL)."),(0,i.kt)("p",null,"Remember to run Powershell in Administrator mode either by right clicking and selecting 'Run as administrator' or by typing PowerShell in 'Run' dialog box of Windows and pressing ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+Shift+Enter")," key combination."),(0,i.kt)("p",null,"Install Ubuntu distribution of Linux by executing the command:\n",(0,i.kt)("inlineCode",{parentName:"p"},"wsl --install --distribution Ubuntu"),"\nor\nInstall Ubuntu distribution of Linux from Microsoft Store by using guide ",(0,i.kt)("a",{parentName:"p",href:"https://learn.microsoft.com/en-us/windows/wsl/install"},"here"),"."),(0,i.kt)("p",null,"Alternatively, you can follow these instructions as well:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://pureinfotech.com/install-wsl-windows-11/"},"How to install WSL")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/install-manual"},"Manual installation steps for WSL"))),(0,i.kt)("p",null,"Once WSL is installed, make sure to:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#set-up-your-linux-username-and-password"},"Set up your Linux username and password")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#update-and-upgrade-packages"},"Update and upgrade packages")),(0,i.kt)("li",{parentName:"ul"},"Verify Ubuntu distribution using the command: 'lsb_release -a'"),(0,i.kt)("li",{parentName:"ul"},"You can verify WSL and Ubuntu installation by using the command in PowerShell: 'wsl -l -v'")),(0,i.kt)("h2",{id:"install-docker-desktop"},"Install Docker Desktop"),(0,i.kt)("p",null,"Install docker desktop with WSL 2 backend. You can find the instructions ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/windows-install/"},"here"),"."),(0,i.kt)("p",null,"Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting ",(0,i.kt)("inlineCode",{parentName:"p"},"Settings > Resources > WSL Integration"),". Enable integration with Ubuntu. Make sure to hit 'Apply & Restart'."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Docker Desktop WSL Distro",src:t(5238).Z,width:"1918",height:"1033"})),(0,i.kt)("h2",{id:"install-node"},"Install Node."),(0,i.kt)("p",null,"Run Powershell in Administrator mode. Run Ubuntu using command : ",(0,i.kt)("inlineCode",{parentName:"p"},"wsl"),". After logging on run the following command: ",(0,i.kt)("inlineCode",{parentName:"p"},"cd ~/")," to ensure that the installation of Node and other packages mentioned below is done in Ubuntu."),(0,i.kt)("p",null,"In your WSL Ubuntu terminal, if node (",(0,i.kt)("inlineCode",{parentName:"p"},"node --version"),") isn't already installed on your machine. You can do so by first installing ",(0,i.kt)("inlineCode",{parentName:"p"},"nvm")," by running following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash\nsource ~/.profile\n\nexport NVM_DIR="$HOME/.nvm"\n[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh" # This loads nvm\n[ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n')),(0,i.kt)("p",null,"You can verify nvm by using ",(0,i.kt)("inlineCode",{parentName:"p"},"nvm --version")," command. Afterwards, install Node (version between 16.0 and 18.0 both inclusive) by using:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"nvm install --lts\n")),(0,i.kt)("p",null,"You can verify node version by using ",(0,i.kt)("inlineCode",{parentName:"p"},"node --version")," command."),(0,i.kt)("h2",{id:"install-python-3"},"Install Python 3"),(0,i.kt)("p",null,"In your WSL Ubuntu terminal, if python 3 (",(0,i.kt)("inlineCode",{parentName:"p"},"pip3 --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y python3-pip\n")),(0,i.kt)("p",null,"You can verify python3 by using ",(0,i.kt)("inlineCode",{parentName:"p"},"python3 --version")," command."),(0,i.kt)("h2",{id:"install-make"},"Install Make"),(0,i.kt)("p",null,"In your WSL Ubuntu terminal, if make (",(0,i.kt)("inlineCode",{parentName:"p"},"make --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y build-essential\n")),(0,i.kt)("p",null,"You can verify make by using ",(0,i.kt)("inlineCode",{parentName:"p"},"make --version")," command."),(0,i.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,i.kt)("p",null,"Clone Ethereal Engine repo on your machine by running following command in WSL Ubuntu terminal. You can check the directory in which you are sitting by the command: ",(0,i.kt)("inlineCode",{parentName:"p"},"pwd")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/etherealengine/etherealengine --depth 1\n")),(0,i.kt)("p",null,"Change directory to the location where etherealengine repo is cloned ",(0,i.kt)("inlineCode",{parentName:"p"},"cd etherealengine"),"\nIf ",(0,i.kt)("inlineCode",{parentName:"p"},".env.local")," file does not exist in the root of your repo folder then create it by duplicating ",(0,i.kt)("inlineCode",{parentName:"p"},".env.local.default"),". Command: ",(0,i.kt)("inlineCode",{parentName:"p"},"cp .env.local.default .env.local")),(0,i.kt)("p",null,"Afterwards, install npm packages using:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm install\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Note: If you face issue related to ",(0,i.kt)("inlineCode",{parentName:"p"},"mediasoup")," while doing npm install. Then remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"mediasoup")," package from ",(0,i.kt)("inlineCode",{parentName:"p"},"packages/instanceserver/package.json")," file of Ethereal Engine source code. And run ",(0,i.kt)("inlineCode",{parentName:"p"},"npm install")," again. Afterwards, run:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm install mediasoup@3 -w @etherealengine/instanceserver\n")),(0,i.kt)("h2",{id:"initialize-mariadb-server"},"Initialize MariaDB server"),(0,i.kt)("p",null,"If you are running the engine for the first time then you will need to initialize the database with tables and data. You can do so by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev-reinit\n")),(0,i.kt)("h2",{id:"start-engine-stack"},"Start Engine Stack"),(0,i.kt)("p",null,"You can run Ethereal Engine stack by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")),(0,i.kt)("p",null,"Now run Ethereal Engine in browser by navigating to ",(0,i.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default"},"this link"),". "),(0,i.kt)("h2",{id:"accept-certificates"},"Accept Certificates"),(0,i.kt)("p",null,"You'll have to tell your browser to ignore the insecure connections when you try to load the website."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates."),(0,i.kt)("li",{parentName:"ol"},"Open Developer tools in your browser by clicking the side menu with three dots, then ",(0,i.kt)("inlineCode",{parentName:"li"},"More tools > Developer tools")," (or use ",(0,i.kt)("inlineCode",{parentName:"li"},"Ctrl+Shift+I"),") and then go to the 'Console' tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.")))}c.isMDXComponent=!0},5238:(e,n,t)=>{t.d(n,{Z:()=>a});const a=t.p+"assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg"}}]); \ No newline at end of file diff --git a/assets/js/17896441.07f91ca7.js b/assets/js/17896441.07f91ca7.js new file mode 100644 index 000000000000..43ea566a7b0f --- /dev/null +++ b/assets/js/17896441.07f91ca7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7918],{903:(e,t,a)=>{a.r(t),a.d(t,{default:()=>pe});var n=a(7294),l=a(833),r=a(902);const o=n.createContext(null);function s(e){let{children:t,content:a}=e;const l=function(e){return(0,n.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(a);return n.createElement(o.Provider,{value:l},t)}function c(){const e=(0,n.useContext)(o);if(null===e)throw new r.i6("DocProvider");return e}function i(){const{metadata:e,frontMatter:t,assets:a}=c();return n.createElement(l.d,{title:e.title,description:e.description,keywords:t.keywords,image:a.image??t.image})}var d=a(6010),m=a(7524),u=a(7462),b=a(5999),p=a(9960);function E(e){const{permalink:t,title:a,subLabel:l,isNext:r}=e;return n.createElement(p.Z,{className:(0,d.Z)("pagination-nav__link",r?"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))}function h(e){const{previous:t,next:a}=e;return n.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,b.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&n.createElement(E,(0,u.Z)({},t,{subLabel:n.createElement(b.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),a&&n.createElement(E,(0,u.Z)({},a,{subLabel:n.createElement(b.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function v(){const{metadata:e}=c();return n.createElement(h,{previous:e.previous,next:e.next})}var g=a(2263),f=a(143),_=a(5281),N=a(373),Z=a(4477);const k={unreleased:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(b.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(b.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 C(e){const t=k[e.versionMetadata.banner];return n.createElement(t,e)}function L(e){let{versionLabel:t,to:a,onClick:l}=e;return n.createElement(b.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(p.Z,{to:a,onClick:l},n.createElement(b.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 T(e){let{className:t,versionMetadata:a}=e;const{siteConfig:{title:l}}=(0,g.Z)(),{pluginId:r}=(0,f.gA)({failfast:!0}),{savePreferredVersionName:o}=(0,N.J)(r),{latestDocSuggestion:s,latestVersionSuggestion:c}=(0,f.Jo)(r),i=s??(m=c).docs.find((e=>e.id===m.mainDocId));var m;return n.createElement("div",{className:(0,d.Z)(t,_.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},n.createElement("div",null,n.createElement(C,{siteTitle:l,versionMetadata:a})),n.createElement("div",{className:"margin-top--md"},n.createElement(L,{versionLabel:c.label,to:i.path,onClick:()=>o(c.name)})))}function U(e){let{className:t}=e;const a=(0,Z.E)();return a.banner?n.createElement(T,{className:t,versionMetadata:a}):null}function w(e){let{className:t}=e;const a=(0,Z.E)();return a.badge?n.createElement("span",{className:(0,d.Z)(t,_.k.docs.docVersionBadge,"badge badge--secondary")},n.createElement(b.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:a.label}},"Version: {versionLabel}")):null}function x(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:a}=e;return n.createElement(b.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:n.createElement("b",null,n.createElement("time",{dateTime:new Date(1e3*t).toISOString()},a))}}," on {date}")}function y(e){let{lastUpdatedBy:t}=e;return n.createElement(b.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:n.createElement("b",null,t)}}," by {user}")}function A(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:a,lastUpdatedBy:l}=e;return n.createElement("span",{className:_.k.common.lastUpdated},n.createElement(b.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&a?n.createElement(x,{lastUpdatedAt:t,formattedLastUpdatedAt:a}):"",byUser:l?n.createElement(y,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}const M={iconEdit:"iconEdit_Z9Sw"};function B(e){let{className:t,...a}=e;return n.createElement("svg",(0,u.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,d.Z)(M.iconEdit,t),"aria-hidden":"true"},a),n.createElement("g",null,n.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function I(e){let{editUrl:t}=e;return n.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:_.k.common.editThisPage},n.createElement(B,null),n.createElement(b.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const V={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function H(e){let{permalink:t,label:a,count:l}=e;return n.createElement(p.Z,{href:t,className:(0,d.Z)(V.tag,l?V.tagWithCount:V.tagRegular)},a,l&&n.createElement("span",null,l))}const P={tags:"tags_jXut",tag:"tag_QGVx"};function D(e){let{tags:t}=e;return n.createElement(n.Fragment,null,n.createElement("b",null,n.createElement(b.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),n.createElement("ul",{className:(0,d.Z)(P.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:a}=e;return n.createElement("li",{key:a,className:P.tag},n.createElement(H,{label:t,permalink:a}))}))))}const S={lastUpdated:"lastUpdated_vwxv"};function F(e){return n.createElement("div",{className:(0,d.Z)(_.k.docs.docFooterTagsRow,"row margin-bottom--sm")},n.createElement("div",{className:"col"},n.createElement(D,e)))}function R(e){let{editUrl:t,lastUpdatedAt:a,lastUpdatedBy:l,formattedLastUpdatedAt:r}=e;return n.createElement("div",{className:(0,d.Z)(_.k.docs.docFooterEditMetaRow,"row")},n.createElement("div",{className:"col"},t&&n.createElement(I,{editUrl:t})),n.createElement("div",{className:(0,d.Z)("col",S.lastUpdated)},(a||l)&&n.createElement(A,{lastUpdatedAt:a,formattedLastUpdatedAt:r,lastUpdatedBy:l})))}function z(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:a,formattedLastUpdatedAt:l,lastUpdatedBy:r,tags:o}=e,s=o.length>0,i=!!(t||a||r);return s||i?n.createElement("footer",{className:(0,d.Z)(_.k.docs.docFooter,"docusaurus-mt-lg")},s&&n.createElement(F,{tags:o}),i&&n.createElement(R,{editUrl:t,lastUpdatedAt:a,lastUpdatedBy:r,formattedLastUpdatedAt:l})):null}var O=a(6043),j=a(3743);const q={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function G(e){let{collapsed:t,...a}=e;return n.createElement("button",(0,u.Z)({type:"button"},a,{className:(0,d.Z)("clean-btn",q.tocCollapsibleButton,!t&&q.tocCollapsibleButtonExpanded,a.className)}),n.createElement(b.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const W={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function J(e){let{toc:t,className:a,minHeadingLevel:l,maxHeadingLevel:r}=e;const{collapsed:o,toggleCollapsed:s}=(0,O.u)({initialState:!0});return n.createElement("div",{className:(0,d.Z)(W.tocCollapsible,!o&&W.tocCollapsibleExpanded,a)},n.createElement(G,{collapsed:o,onClick:s}),n.createElement(O.z,{lazy:!0,className:W.tocCollapsibleContent,collapsed:o},n.createElement(j.Z,{toc:t,minHeadingLevel:l,maxHeadingLevel:r})))}const Q={tocMobile:"tocMobile_ITEo"};function X(){const{toc:e,frontMatter:t}=c();return n.createElement(J,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.Z)(_.k.docs.docTocMobile,Q.tocMobile)})}var Y=a(9407);function $(){const{toc:e,frontMatter:t}=c();return n.createElement(Y.Z,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:_.k.docs.docTocDesktop})}var K=a(2503),ee=a(7432);function te(e){let{children:t}=e;const a=function(){const{metadata:e,frontMatter:t,contentTitle:a}=c();return t.hide_title||void 0!==a?null:e.title}();return n.createElement("div",{className:(0,d.Z)(_.k.docs.docMarkdown,"markdown")},a&&n.createElement("header",null,n.createElement(K.Z,{as:"h1"},a)),n.createElement(ee.Z,null,t))}var ae=a(2802),ne=a(8596),le=a(4996);function re(e){return n.createElement("svg",(0,u.Z)({viewBox:"0 0 24 24"},e),n.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 oe={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function se(){const e=(0,le.Z)("/");return n.createElement("li",{className:"breadcrumbs__item"},n.createElement(p.Z,{"aria-label":(0,b.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},n.createElement(re,{className:oe.breadcrumbHomeIcon})))}const ce={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function ie(e){let{children:t,href:a,isLast:l}=e;const r="breadcrumbs__link";return l?n.createElement("span",{className:r,itemProp:"name"},t):a?n.createElement(p.Z,{className:r,href:a,itemProp:"item"},n.createElement("span",{itemProp:"name"},t)):n.createElement("span",{className:r},t)}function de(e){let{children:t,active:a,index:l,addMicrodata:r}=e;return n.createElement("li",(0,u.Z)({},r&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.Z)("breadcrumbs__item",{"breadcrumbs__item--active":a})}),t,n.createElement("meta",{itemProp:"position",content:String(l+1)}))}function me(){const e=(0,ae.s1)(),t=(0,ne.Ns)();return e?n.createElement("nav",{className:(0,d.Z)(_.k.docs.docBreadcrumbs,ce.breadcrumbsContainer),"aria-label":(0,b.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},n.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&n.createElement(se,null),e.map(((t,a)=>{const l=a===e.length-1;return n.createElement(de,{key:a,active:l,index:a,addMicrodata:!!t.href},n.createElement(ie,{href:t.href,isLast:l},t.label))})))):null}const ue={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function be(e){let{children:t}=e;const a=function(){const{frontMatter:e,toc:t}=c(),a=(0,m.i)(),l=e.hide_table_of_contents,r=!l&&t.length>0;return{hidden:l,mobile:r?n.createElement(X,null):void 0,desktop:!r||"desktop"!==a&&"ssr"!==a?void 0:n.createElement($,null)}}();return n.createElement("div",{className:"row"},n.createElement("div",{className:(0,d.Z)("col",!a.hidden&&ue.docItemCol)},n.createElement(U,null),n.createElement("div",{className:ue.docItemContainer},n.createElement("article",null,n.createElement(me,null),n.createElement(w,null),a.mobile,n.createElement(te,null,t),n.createElement(z,null)),n.createElement(v,null))),a.desktop&&n.createElement("div",{className:"col col--3"},a.desktop))}function pe(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,a=e.content;return n.createElement(s,{content:e.content},n.createElement(l.FG,{className:t},n.createElement(i,null),n.createElement(be,null,n.createElement(a,null))))}},4477:(e,t,a)=>{a.d(t,{E:()=>s,q:()=>o});var n=a(7294),l=a(902);const r=n.createContext(null);function o(e){let{children:t,version:a}=e;return n.createElement(r.Provider,{value:a},t)}function s(){const e=(0,n.useContext)(r);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/1a4e3797.dd8146f2.js b/assets/js/1a4e3797.dd8146f2.js new file mode 100644 index 000000000000..7cb9dd049db4 --- /dev/null +++ b/assets/js/1a4e3797.dd8146f2.js @@ -0,0 +1,2 @@ +/*! For license information please see 1a4e3797.dd8146f2.js.LICENSE.txt */ +(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7920],{7331:e=>{function t(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=t,t.prototype._events=void 0,t.prototype._maxListeners=void 0,t.defaultMaxListeners=10,t.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},t.prototype.emit=function(e){var t,a,s,c,u,o;if(this._events||(this._events={}),"error"===e&&(!this._events.error||n(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i(a=this._events[e]))return!1;if(r(a))switch(arguments.length){case 1:a.call(this);break;case 2:a.call(this,arguments[1]);break;case 3:a.call(this,arguments[1],arguments[2]);break;default:c=Array.prototype.slice.call(arguments,1),a.apply(this,c)}else if(n(a))for(c=Array.prototype.slice.call(arguments,1),s=(o=a.slice()).length,u=0;u0&&this._events[e].length>s&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}return i.listener=t,this.on(e,i),this},t.prototype.removeListener=function(e,t){var i,a,s,c;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(s=(i=this._events[e]).length,a=-1,i===t||r(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(n(i)){for(c=s;c-- >0;)if(i[c]===t||i[c].listener&&i[c].listener===t){a=c;break}if(a<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(a,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},t.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},t.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},t.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},t.listenerCount=function(e,t){return e.listenerCount(t)}},8131:(e,t,r)=>{"use strict";var n=r(9374),i=r(7775),a=r(3076);function s(e,t,r){return new n(e,t,r)}s.version=r(4336),s.AlgoliaSearchHelper=n,s.SearchParameters=i,s.SearchResults=a,e.exports=s},8078:(e,t,r)=>{"use strict";var n=r(7331);function i(e,t){this.main=e,this.fn=t,this.lastResults=null}r(4853)(i,n),i.prototype.detach=function(){this.removeAllListeners(),this.main.detachDerivedHelper(this)},i.prototype.getModifiedState=function(e){return this.fn(e)},e.exports=i},2437:(e,t,r)=>{"use strict";var n=r(2344),i=r(116),a=r(9803),s={addRefinement:function(e,t,r){if(s.isRefined(e,t,r))return e;var i=""+r,a=e[t]?e[t].concat(i):[i],c={};return c[t]=a,n({},c,e)},removeRefinement:function(e,t,r){if(void 0===r)return s.clearRefinement(e,(function(e,r){return t===r}));var n=""+r;return s.clearRefinement(e,(function(e,r){return t===r&&n===e}))},toggleRefinement:function(e,t,r){if(void 0===r)throw new Error("toggleRefinement should be used with a value");return s.isRefined(e,t,r)?s.removeRefinement(e,t,r):s.addRefinement(e,t,r)},clearRefinement:function(e,t,r){if(void 0===t)return i(e)?{}:e;if("string"==typeof t)return a(e,[t]);if("function"==typeof t){var n=!1,s=Object.keys(e).reduce((function(i,a){var s=e[a]||[],c=s.filter((function(e){return!t(e,a,r)}));return c.length!==s.length&&(n=!0),i[a]=c,i}),{});return n?s:e}},isRefined:function(e,t,r){var n=Boolean(e[t])&&e[t].length>0;if(void 0===r||!n)return n;var i=""+r;return-1!==e[t].indexOf(i)}};e.exports=s},7775:(e,t,r)=>{"use strict";var n=r(2344),i=r(7888),a=r(2686),s=r(185),c=r(116),u=r(9803),o=r(8023),h=r(6801),f=r(2437);function l(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((function(e,r){return l(t[r],e)})):e===t}function m(e){var t=e?m._parseNumbers(e):{};void 0===t.userToken||h(t.userToken)||console.warn("[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}"),this.facets=t.facets||[],this.disjunctiveFacets=t.disjunctiveFacets||[],this.hierarchicalFacets=t.hierarchicalFacets||[],this.facetsRefinements=t.facetsRefinements||{},this.facetsExcludes=t.facetsExcludes||{},this.disjunctiveFacetsRefinements=t.disjunctiveFacetsRefinements||{},this.numericRefinements=t.numericRefinements||{},this.tagRefinements=t.tagRefinements||[],this.hierarchicalFacetsRefinements=t.hierarchicalFacetsRefinements||{};var r=this;Object.keys(t).forEach((function(e){var n=-1!==m.PARAMETERS.indexOf(e),i=void 0!==t[e];!n&&i&&(r[e]=t[e])}))}m.PARAMETERS=Object.keys(new m),m._parseNumbers=function(e){if(e instanceof m)return e;var t={};if(["aroundPrecision","aroundRadius","getRankingInfo","minWordSizefor2Typos","minWordSizefor1Typo","page","maxValuesPerFacet","distinct","minimumAroundRadius","hitsPerPage","minProximity"].forEach((function(r){var n=e[r];if("string"==typeof n){var i=parseFloat(n);t[r]=isNaN(i)?n:i}})),Array.isArray(e.insideBoundingBox)&&(t.insideBoundingBox=e.insideBoundingBox.map((function(e){return Array.isArray(e)?e.map((function(e){return parseFloat(e)})):e}))),e.numericRefinements){var r={};Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t]||{};r[t]={},Object.keys(n).forEach((function(e){var i=n[e].map((function(e){return Array.isArray(e)?e.map((function(e){return"string"==typeof e?parseFloat(e):e})):"string"==typeof e?parseFloat(e):e}));r[t][e]=i}))})),t.numericRefinements=r}return s({},e,t)},m.make=function(e){var t=new m(e);return(e.hierarchicalFacets||[]).forEach((function(e){if(e.rootPath){var r=t.getHierarchicalRefinement(e.name);r.length>0&&0!==r[0].indexOf(e.rootPath)&&(t=t.clearRefinements(e.name)),0===(r=t.getHierarchicalRefinement(e.name)).length&&(t=t.toggleHierarchicalFacetRefinement(e.name,e.rootPath))}})),t},m.validate=function(e,t){var r=t||{};return e.tagFilters&&r.tagRefinements&&r.tagRefinements.length>0?new Error("[Tags] Cannot switch from the managed tag API to the advanced API. It is probably an error, if it is really what you want, you should first clear the tags with clearTags method."):e.tagRefinements.length>0&&r.tagFilters?new Error("[Tags] Cannot switch from the advanced tag API to the managed API. It is probably an error, if it is not, you should first clear the tags with clearTags method."):e.numericFilters&&r.numericRefinements&&c(r.numericRefinements)?new Error("[Numeric filters] Can't switch from the advanced to the managed API. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):c(e.numericRefinements)&&r.numericFilters?new Error("[Numeric filters] Can't switch from the managed API to the advanced. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):null},m.prototype={constructor:m,clearRefinements:function(e){var t={numericRefinements:this._clearNumericRefinements(e),facetsRefinements:f.clearRefinement(this.facetsRefinements,e,"conjunctiveFacet"),facetsExcludes:f.clearRefinement(this.facetsExcludes,e,"exclude"),disjunctiveFacetsRefinements:f.clearRefinement(this.disjunctiveFacetsRefinements,e,"disjunctiveFacet"),hierarchicalFacetsRefinements:f.clearRefinement(this.hierarchicalFacetsRefinements,e,"hierarchicalFacet")};return t.numericRefinements===this.numericRefinements&&t.facetsRefinements===this.facetsRefinements&&t.facetsExcludes===this.facetsExcludes&&t.disjunctiveFacetsRefinements===this.disjunctiveFacetsRefinements&&t.hierarchicalFacetsRefinements===this.hierarchicalFacetsRefinements?this:this.setQueryParameters(t)},clearTags:function(){return void 0===this.tagFilters&&0===this.tagRefinements.length?this:this.setQueryParameters({tagFilters:void 0,tagRefinements:[]})},setIndex:function(e){return e===this.index?this:this.setQueryParameters({index:e})},setQuery:function(e){return e===this.query?this:this.setQueryParameters({query:e})},setPage:function(e){return e===this.page?this:this.setQueryParameters({page:e})},setFacets:function(e){return this.setQueryParameters({facets:e})},setDisjunctiveFacets:function(e){return this.setQueryParameters({disjunctiveFacets:e})},setHitsPerPage:function(e){return this.hitsPerPage===e?this:this.setQueryParameters({hitsPerPage:e})},setTypoTolerance:function(e){return this.typoTolerance===e?this:this.setQueryParameters({typoTolerance:e})},addNumericRefinement:function(e,t,r){var n=o(r);if(this.isNumericRefined(e,t,n))return this;var i=s({},this.numericRefinements);return i[e]=s({},i[e]),i[e][t]?(i[e][t]=i[e][t].slice(),i[e][t].push(n)):i[e][t]=[n],this.setQueryParameters({numericRefinements:i})},getConjunctiveRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsRefinements[e]||[]},getDisjunctiveRefinements:function(e){return this.isDisjunctiveFacet(e)&&this.disjunctiveFacetsRefinements[e]||[]},getHierarchicalRefinement:function(e){return this.hierarchicalFacetsRefinements[e]||[]},getExcludeRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsExcludes[e]||[]},removeNumericRefinement:function(e,t,r){var n=r;return void 0!==n?this.isNumericRefined(e,t,n)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,i){return i===e&&r.op===t&&l(r.val,o(n))}))}):this:void 0!==t?this.isNumericRefined(e,t)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,n){return n===e&&r.op===t}))}):this:this.isNumericRefined(e)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(t,r){return r===e}))}):this},getNumericRefinements:function(e){return this.numericRefinements[e]||{}},getNumericRefinement:function(e,t){return this.numericRefinements[e]&&this.numericRefinements[e][t]},_clearNumericRefinements:function(e){if(void 0===e)return c(this.numericRefinements)?{}:this.numericRefinements;if("string"==typeof e)return u(this.numericRefinements,[e]);if("function"==typeof e){var t=!1,r=this.numericRefinements,n=Object.keys(r).reduce((function(n,i){var a=r[i],s={};return a=a||{},Object.keys(a).forEach((function(r){var n=a[r]||[],c=[];n.forEach((function(t){e({val:t,op:r},i,"numeric")||c.push(t)})),c.length!==n.length&&(t=!0),s[r]=c})),n[i]=s,n}),{});return t?n:this.numericRefinements}},addFacet:function(e){return this.isConjunctiveFacet(e)?this:this.setQueryParameters({facets:this.facets.concat([e])})},addDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this:this.setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.concat([e])})},addHierarchicalFacet:function(e){if(this.isHierarchicalFacet(e.name))throw new Error("Cannot declare two hierarchical facets with the same name: `"+e.name+"`");return this.setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.concat([e])})},addFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this:this.setQueryParameters({facetsRefinements:f.addRefinement(this.facetsRefinements,e,t)})},addExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this:this.setQueryParameters({facetsExcludes:f.addRefinement(this.facetsExcludes,e,t)})},addDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this:this.setQueryParameters({disjunctiveFacetsRefinements:f.addRefinement(this.disjunctiveFacetsRefinements,e,t)})},addTagRefinement:function(e){if(this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.concat(e)};return this.setQueryParameters(t)},removeFacet:function(e){return this.isConjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({facets:this.facets.filter((function(t){return t!==e}))}):this},removeDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.filter((function(t){return t!==e}))}):this},removeHierarchicalFacet:function(e){return this.isHierarchicalFacet(e)?this.clearRefinements(e).setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.filter((function(t){return t.name!==e}))}):this},removeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this.setQueryParameters({facetsRefinements:f.removeRefinement(this.facetsRefinements,e,t)}):this},removeExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this.setQueryParameters({facetsExcludes:f.removeRefinement(this.facetsExcludes,e,t)}):this},removeDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this.setQueryParameters({disjunctiveFacetsRefinements:f.removeRefinement(this.disjunctiveFacetsRefinements,e,t)}):this},removeTagRefinement:function(e){if(!this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.filter((function(t){return t!==e}))};return this.setQueryParameters(t)},toggleRefinement:function(e,t){return this.toggleFacetRefinement(e,t)},toggleFacetRefinement:function(e,t){if(this.isHierarchicalFacet(e))return this.toggleHierarchicalFacetRefinement(e,t);if(this.isConjunctiveFacet(e))return this.toggleConjunctiveFacetRefinement(e,t);if(this.isDisjunctiveFacet(e))return this.toggleDisjunctiveFacetRefinement(e,t);throw new Error("Cannot refine the undeclared facet "+e+"; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets")},toggleConjunctiveFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsRefinements:f.toggleRefinement(this.facetsRefinements,e,t)})},toggleExcludeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsExcludes:f.toggleRefinement(this.facetsExcludes,e,t)})},toggleDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return this.setQueryParameters({disjunctiveFacetsRefinements:f.toggleRefinement(this.disjunctiveFacetsRefinements,e,t)})},toggleHierarchicalFacetRefinement:function(e,t){if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration");var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e)),i={};return void 0!==this.hierarchicalFacetsRefinements[e]&&this.hierarchicalFacetsRefinements[e].length>0&&(this.hierarchicalFacetsRefinements[e][0]===t||0===this.hierarchicalFacetsRefinements[e][0].indexOf(t+r))?-1===t.indexOf(r)?i[e]=[]:i[e]=[t.slice(0,t.lastIndexOf(r))]:i[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},i,this.hierarchicalFacetsRefinements)})},addHierarchicalFacetRefinement:function(e,t){if(this.isHierarchicalFacetRefined(e))throw new Error(e+" is already refined.");if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration.");var r={};return r[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},r,this.hierarchicalFacetsRefinements)})},removeHierarchicalFacetRefinement:function(e){if(!this.isHierarchicalFacetRefined(e))return this;var t={};return t[e]=[],this.setQueryParameters({hierarchicalFacetsRefinements:n({},t,this.hierarchicalFacetsRefinements)})},toggleTagRefinement:function(e){return this.isTagRefined(e)?this.removeTagRefinement(e):this.addTagRefinement(e)},isDisjunctiveFacet:function(e){return this.disjunctiveFacets.indexOf(e)>-1},isHierarchicalFacet:function(e){return void 0!==this.getHierarchicalFacetByName(e)},isConjunctiveFacet:function(e){return this.facets.indexOf(e)>-1},isFacetRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsRefinements,e,t)},isExcludeRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsExcludes,e,t)},isDisjunctiveFacetRefined:function(e,t){return!!this.isDisjunctiveFacet(e)&&f.isRefined(this.disjunctiveFacetsRefinements,e,t)},isHierarchicalFacetRefined:function(e,t){if(!this.isHierarchicalFacet(e))return!1;var r=this.getHierarchicalRefinement(e);return t?-1!==r.indexOf(t):r.length>0},isNumericRefined:function(e,t,r){if(void 0===r&&void 0===t)return Boolean(this.numericRefinements[e]);var n=this.numericRefinements[e]&&void 0!==this.numericRefinements[e][t];if(void 0===r||!n)return n;var a,s,c=o(r),u=void 0!==(a=this.numericRefinements[e][t],s=c,i(a,(function(e){return l(e,s)})));return n&&u},isTagRefined:function(e){return-1!==this.tagRefinements.indexOf(e)},getRefinedDisjunctiveFacets:function(){var e=this,t=a(Object.keys(this.numericRefinements).filter((function(t){return Object.keys(e.numericRefinements[t]).length>0})),this.disjunctiveFacets);return Object.keys(this.disjunctiveFacetsRefinements).filter((function(t){return e.disjunctiveFacetsRefinements[t].length>0})).concat(t).concat(this.getRefinedHierarchicalFacets()).sort()},getRefinedHierarchicalFacets:function(){var e=this;return a(this.hierarchicalFacets.map((function(e){return e.name})),Object.keys(this.hierarchicalFacetsRefinements).filter((function(t){return e.hierarchicalFacetsRefinements[t].length>0}))).sort()},getUnrefinedDisjunctiveFacets:function(){var e=this.getRefinedDisjunctiveFacets();return this.disjunctiveFacets.filter((function(t){return-1===e.indexOf(t)}))},managedParameters:["index","facets","disjunctiveFacets","facetsRefinements","hierarchicalFacets","facetsExcludes","disjunctiveFacetsRefinements","numericRefinements","tagRefinements","hierarchicalFacetsRefinements"],getQueryParams:function(){var e=this.managedParameters,t={},r=this;return Object.keys(this).forEach((function(n){var i=r[n];-1===e.indexOf(n)&&void 0!==i&&(t[n]=i)})),t},setQueryParameter:function(e,t){if(this[e]===t)return this;var r={};return r[e]=t,this.setQueryParameters(r)},setQueryParameters:function(e){if(!e)return this;var t=m.validate(this,e);if(t)throw t;var r=this,n=m._parseNumbers(e),i=Object.keys(this).reduce((function(e,t){return e[t]=r[t],e}),{}),a=Object.keys(n).reduce((function(e,t){var r=void 0!==e[t],i=void 0!==n[t];return r&&!i?u(e,[t]):(i&&(e[t]=n[t]),e)}),i);return new this.constructor(a)},resetPage:function(){return void 0===this.page?this:this.setPage(0)},_getHierarchicalFacetSortBy:function(e){return e.sortBy||["isRefined:desc","name:asc"]},_getHierarchicalFacetSeparator:function(e){return e.separator||" > "},_getHierarchicalRootPath:function(e){return e.rootPath||null},_getHierarchicalShowParentLevel:function(e){return"boolean"!=typeof e.showParentLevel||e.showParentLevel},getHierarchicalFacetByName:function(e){return i(this.hierarchicalFacets,(function(t){return t.name===e}))},getHierarchicalFacetBreadcrumb:function(e){if(!this.isHierarchicalFacet(e))return[];var t=this.getHierarchicalRefinement(e)[0];if(!t)return[];var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e));return t.split(r).map((function(e){return e.trim()}))},toString:function(){return JSON.stringify(this,null,2)}},e.exports=m},210:(e,t,r)=>{"use strict";e.exports=function(e){return function(t,r){var n=e.hierarchicalFacets[r],o=e.hierarchicalFacetsRefinements[n.name]&&e.hierarchicalFacetsRefinements[n.name][0]||"",h=e._getHierarchicalFacetSeparator(n),f=e._getHierarchicalRootPath(n),l=e._getHierarchicalShowParentLevel(n),m=a(e._getHierarchicalFacetSortBy(n)),d=t.every((function(e){return e.exhaustive})),p=function(e,t,r,n,a){return function(o,h,f){var l=o;if(f>0){var m=0;for(l=o;m{"use strict";var n=r(4587),i=r(2344),a=r(4039),s=r(7888),c=r(9725),u=r(2293),o=r(185),h=r(2148),f=a.escapeFacetValue,l=a.unescapeFacetValue,m=r(210);function d(e){var t={};return e.forEach((function(e,r){t[e]=r})),t}function p(e,t,r){t&&t[r]&&(e.stats=t[r])}function v(e,t,r){var a=t[0];this._rawResults=t;var u=this;Object.keys(a).forEach((function(e){u[e]=a[e]})),Object.keys(r||{}).forEach((function(e){u[e]=r[e]})),this.processingTimeMS=t.reduce((function(e,t){return void 0===t.processingTimeMS?e:e+t.processingTimeMS}),0),this.disjunctiveFacets=[],this.hierarchicalFacets=e.hierarchicalFacets.map((function(){return[]})),this.facets=[];var h=e.getRefinedDisjunctiveFacets(),f=d(e.facets),v=d(e.disjunctiveFacets),g=1,y=a.facets||{};Object.keys(y).forEach((function(t){var r,n,i=y[t],o=(r=e.hierarchicalFacets,n=t,s(r,(function(e){return(e.attributes||[]).indexOf(n)>-1})));if(o){var h=o.attributes.indexOf(t),l=c(e.hierarchicalFacets,(function(e){return e.name===o.name}));u.hierarchicalFacets[l][h]={attribute:t,data:i,exhaustive:a.exhaustiveFacetsCount}}else{var m,d=-1!==e.disjunctiveFacets.indexOf(t),g=-1!==e.facets.indexOf(t);d&&(m=v[t],u.disjunctiveFacets[m]={name:t,data:i,exhaustive:a.exhaustiveFacetsCount},p(u.disjunctiveFacets[m],a.facets_stats,t)),g&&(m=f[t],u.facets[m]={name:t,data:i,exhaustive:a.exhaustiveFacetsCount},p(u.facets[m],a.facets_stats,t))}})),this.hierarchicalFacets=n(this.hierarchicalFacets),h.forEach((function(r){var n=t[g],s=n&&n.facets?n.facets:{},h=e.getHierarchicalFacetByName(r);Object.keys(s).forEach((function(t){var r,f=s[t];if(h){r=c(e.hierarchicalFacets,(function(e){return e.name===h.name}));var m=c(u.hierarchicalFacets[r],(function(e){return e.attribute===t}));if(-1===m)return;u.hierarchicalFacets[r][m].data=o({},u.hierarchicalFacets[r][m].data,f)}else{r=v[t];var d=a.facets&&a.facets[t]||{};u.disjunctiveFacets[r]={name:t,data:i({},f,d),exhaustive:n.exhaustiveFacetsCount},p(u.disjunctiveFacets[r],n.facets_stats,t),e.disjunctiveFacetsRefinements[t]&&e.disjunctiveFacetsRefinements[t].forEach((function(n){!u.disjunctiveFacets[r].data[n]&&e.disjunctiveFacetsRefinements[t].indexOf(l(n))>-1&&(u.disjunctiveFacets[r].data[n]=0)}))}})),g++})),e.getRefinedHierarchicalFacets().forEach((function(r){var n=e.getHierarchicalFacetByName(r),a=e._getHierarchicalFacetSeparator(n),s=e.getHierarchicalRefinement(r);0===s.length||s[0].split(a).length<2||t.slice(g).forEach((function(t){var r=t&&t.facets?t.facets:{};Object.keys(r).forEach((function(t){var o=r[t],h=c(e.hierarchicalFacets,(function(e){return e.name===n.name})),f=c(u.hierarchicalFacets[h],(function(e){return e.attribute===t}));if(-1!==f){var l={};if(s.length>0){var m=s[0].split(a)[0];l[m]=u.hierarchicalFacets[h][f].data[m]}u.hierarchicalFacets[h][f].data=i(l,o,u.hierarchicalFacets[h][f].data)}})),g++}))})),Object.keys(e.facetsExcludes).forEach((function(t){var r=e.facetsExcludes[t],n=f[t];u.facets[n]={name:t,data:y[t],exhaustive:a.exhaustiveFacetsCount},r.forEach((function(e){u.facets[n]=u.facets[n]||{name:t},u.facets[n].data=u.facets[n].data||{},u.facets[n].data[e]=0}))})),this.hierarchicalFacets=this.hierarchicalFacets.map(m(e)),this.facets=n(this.facets),this.disjunctiveFacets=n(this.disjunctiveFacets),this._state=e}function g(e,t){function r(e){return e.name===t}if(e._state.isConjunctiveFacet(t)){var n=s(e.facets,r);return n?Object.keys(n.data).map((function(r){var i=f(r);return{name:r,escapedValue:i,count:n.data[r],isRefined:e._state.isFacetRefined(t,i),isExcluded:e._state.isExcludeRefined(t,r)}})):[]}if(e._state.isDisjunctiveFacet(t)){var i=s(e.disjunctiveFacets,r);return i?Object.keys(i.data).map((function(r){var n=f(r);return{name:r,escapedValue:n,count:i.data[r],isRefined:e._state.isDisjunctiveFacetRefined(t,n)}})):[]}if(e._state.isHierarchicalFacet(t)){var a=s(e.hierarchicalFacets,r);if(!a)return a;var c=e._state.getHierarchicalFacetByName(t),u=e._state._getHierarchicalFacetSeparator(c),o=l(e._state.getHierarchicalRefinement(t)[0]||"");0===o.indexOf(c.rootPath)&&(o=o.replace(c.rootPath+u,""));var h=o.split(u);return h.unshift(t),y(a,h,0),a}}function y(e,t,r){e.isRefined=e.name===t[r],e.data&&e.data.forEach((function(e){y(e,t,r+1)}))}function R(e,t,r,n){if(n=n||0,Array.isArray(t))return e(t,r[n]);if(!t.data||0===t.data.length)return t;var a=t.data.map((function(t){return R(e,t,r,n+1)})),s=e(a,r[n]);return i({data:s},t)}function F(e,t){var r=s(e,(function(e){return e.name===t}));return r&&r.stats}function b(e,t,r,n,i){var a=s(i,(function(e){return e.name===r})),c=a&&a.data&&a.data[n]?a.data[n]:0,u=a&&a.exhaustive||!1;return{type:t,attributeName:r,name:n,count:c,exhaustive:u}}v.prototype.getFacetByName=function(e){function t(t){return t.name===e}return s(this.facets,t)||s(this.disjunctiveFacets,t)||s(this.hierarchicalFacets,t)},v.DEFAULT_SORT=["isRefined:desc","count:desc","name:asc"],v.prototype.getFacetValues=function(e,t){var r=g(this,e);if(r){var n,a=i({},t,{sortBy:v.DEFAULT_SORT,facetOrdering:!(t&&t.sortBy)}),s=this;if(Array.isArray(r))n=[e];else n=s._state.getHierarchicalFacetByName(r.name).attributes;return R((function(e,t){if(a.facetOrdering){var r=function(e,t){return e.renderingContent&&e.renderingContent.facetOrdering&&e.renderingContent.facetOrdering.values&&e.renderingContent.facetOrdering.values[t]}(s,t);if(r)return function(e,t){var r=[],n=[],i=(t.order||[]).reduce((function(e,t,r){return e[t]=r,e}),{});e.forEach((function(e){var t=e.path||e.name;void 0!==i[t]?r[i[t]]=e:n.push(e)})),r=r.filter((function(e){return e}));var a,s=t.sortRemainingBy;return"hidden"===s?r:(a="alpha"===s?[["path","name"],["asc","asc"]]:[["count"],["desc"]],r.concat(h(n,a[0],a[1])))}(e,r)}if(Array.isArray(a.sortBy)){var n=u(a.sortBy,v.DEFAULT_SORT);return h(e,n[0],n[1])}if("function"==typeof a.sortBy)return function(e,t){return t.sort(e)}(a.sortBy,e);throw new Error("options.sortBy is optional but if defined it must be either an array of string (predicates) or a sorting function")}),r,n)}},v.prototype.getFacetStats=function(e){return this._state.isConjunctiveFacet(e)?F(this.facets,e):this._state.isDisjunctiveFacet(e)?F(this.disjunctiveFacets,e):void 0},v.prototype.getRefinements=function(){var e=this._state,t=this,r=[];return Object.keys(e.facetsRefinements).forEach((function(n){e.facetsRefinements[n].forEach((function(i){r.push(b(e,"facet",n,i,t.facets))}))})),Object.keys(e.facetsExcludes).forEach((function(n){e.facetsExcludes[n].forEach((function(i){r.push(b(e,"exclude",n,i,t.facets))}))})),Object.keys(e.disjunctiveFacetsRefinements).forEach((function(n){e.disjunctiveFacetsRefinements[n].forEach((function(i){r.push(b(e,"disjunctive",n,i,t.disjunctiveFacets))}))})),Object.keys(e.hierarchicalFacetsRefinements).forEach((function(n){e.hierarchicalFacetsRefinements[n].forEach((function(i){r.push(function(e,t,r,n){var i=e.getHierarchicalFacetByName(t),a=e._getHierarchicalFacetSeparator(i),c=r.split(a),u=s(n,(function(e){return e.name===t})),o=c.reduce((function(e,t){var r=e&&s(e.data,(function(e){return e.name===t}));return void 0!==r?r:e}),u),h=o&&o.count||0,f=o&&o.exhaustive||!1,l=o&&o.path||"";return{type:"hierarchical",attributeName:t,name:l,count:h,exhaustive:f}}(e,n,i,t.hierarchicalFacets))}))})),Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t];Object.keys(n).forEach((function(e){n[e].forEach((function(n){r.push({type:"numeric",attributeName:t,name:n,numericValue:n,operator:e})}))}))})),e.tagRefinements.forEach((function(e){r.push({type:"tag",attributeName:"_tags",name:e})})),r},e.exports=v},9374:(e,t,r)=>{"use strict";var n=r(7331),i=r(8078),a=r(4039).escapeFacetValue,s=r(4853),c=r(185),u=r(116),o=r(9803),h=r(6394),f=r(7775),l=r(3076),m=r(4336);function d(e,t,r){"function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+m+")"),this.setClient(e);var n=r||{};n.index=t,this.state=f.make(n),this.lastResults=null,this._queryId=0,this._lastQueryIdReceived=-1,this.derivedHelpers=[],this._currentNbQueries=0}function p(e){if(e<0)throw new Error("Page requested below 0.");return this._change({state:this.state.setPage(e),isPageReset:!1}),this}function v(){return this.state.page}s(d,n),d.prototype.search=function(){return this._search({onlyWithDerivedHelpers:!1}),this},d.prototype.searchOnlyWithDerivedHelpers=function(){return this._search({onlyWithDerivedHelpers:!0}),this},d.prototype.getQuery=function(){var e=this.state;return h._getHitsSearchParams(e)},d.prototype.searchOnce=function(e,t){var r=e?this.state.setQueryParameters(e):this.state,n=h._getQueries(r.index,r),i=this;if(this._currentNbQueries++,this.emit("searchOnce",{state:r}),!t)return this.client.search(n).then((function(e){return i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),{content:new l(r,e.results),state:r,_originalResponse:e}}),(function(e){throw i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),e}));this.client.search(n).then((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(null,new l(r,e.results),r)})).catch((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(e,null,r)}))},d.prototype.findAnswers=function(e){console.warn("[algoliasearch-helper] answers is no longer supported");var t=this.state,r=this.derivedHelpers[0];if(!r)return Promise.resolve([]);var n=r.getModifiedState(t),i=c({attributesForPrediction:e.attributesForPrediction,nbHits:e.nbHits},{params:o(h._getHitsSearchParams(n),["attributesToSnippet","hitsPerPage","restrictSearchableAttributes","snippetEllipsisText"])}),a="search for answers was called, but this client does not have a function client.initIndex(index).findAnswers";if("function"!=typeof this.client.initIndex)throw new Error(a);var s=this.client.initIndex(n.index);if("function"!=typeof s.findAnswers)throw new Error(a);return s.findAnswers(n.query,e.queryLanguages,i)},d.prototype.searchForFacetValues=function(e,t,r,n){var i="function"==typeof this.client.searchForFacetValues,s="function"==typeof this.client.initIndex;if(!i&&!s&&"function"!=typeof this.client.search)throw new Error("search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues");var c=this.state.setQueryParameters(n||{}),u=c.isDisjunctiveFacet(e),o=h.getSearchForFacetQuery(e,t,r,c);this._currentNbQueries++;var f,l=this;return i?f=this.client.searchForFacetValues([{indexName:c.index,params:o}]):s?f=this.client.initIndex(c.index).searchForFacetValues(o):(delete o.facetName,f=this.client.search([{type:"facet",facet:e,indexName:c.index,params:o}]).then((function(e){return e.results[0]}))),this.emit("searchForFacetValues",{state:c,facet:e,query:t}),f.then((function(t){return l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),(t=Array.isArray(t)?t[0]:t).facetHits.forEach((function(t){t.escapedValue=a(t.value),t.isRefined=u?c.isDisjunctiveFacetRefined(e,t.escapedValue):c.isFacetRefined(e,t.escapedValue)})),t}),(function(e){throw l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),e}))},d.prototype.setQuery=function(e){return this._change({state:this.state.resetPage().setQuery(e),isPageReset:!0}),this},d.prototype.clearRefinements=function(e){return this._change({state:this.state.resetPage().clearRefinements(e),isPageReset:!0}),this},d.prototype.clearTags=function(){return this._change({state:this.state.resetPage().clearTags(),isPageReset:!0}),this},d.prototype.addDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addDisjunctiveRefine=function(){return this.addDisjunctiveFacetRefinement.apply(this,arguments)},d.prototype.addHierarchicalFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addHierarchicalFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().addNumericRefinement(e,t,r),isPageReset:!0}),this},d.prototype.addFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addRefine=function(){return this.addFacetRefinement.apply(this,arguments)},d.prototype.addFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().addExcludeRefinement(e,t),isPageReset:!0}),this},d.prototype.addExclude=function(){return this.addFacetExclusion.apply(this,arguments)},d.prototype.addTag=function(e){return this._change({state:this.state.resetPage().addTagRefinement(e),isPageReset:!0}),this},d.prototype.removeNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().removeNumericRefinement(e,t,r),isPageReset:!0}),this},d.prototype.removeDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.removeDisjunctiveRefine=function(){return this.removeDisjunctiveFacetRefinement.apply(this,arguments)},d.prototype.removeHierarchicalFacetRefinement=function(e){return this._change({state:this.state.resetPage().removeHierarchicalFacetRefinement(e),isPageReset:!0}),this},d.prototype.removeFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.removeRefine=function(){return this.removeFacetRefinement.apply(this,arguments)},d.prototype.removeFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().removeExcludeRefinement(e,t),isPageReset:!0}),this},d.prototype.removeExclude=function(){return this.removeFacetExclusion.apply(this,arguments)},d.prototype.removeTag=function(e){return this._change({state:this.state.resetPage().removeTagRefinement(e),isPageReset:!0}),this},d.prototype.toggleFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().toggleExcludeFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.toggleExclude=function(){return this.toggleFacetExclusion.apply(this,arguments)},d.prototype.toggleRefinement=function(e,t){return this.toggleFacetRefinement(e,t)},d.prototype.toggleFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().toggleFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.toggleRefine=function(){return this.toggleFacetRefinement.apply(this,arguments)},d.prototype.toggleTag=function(e){return this._change({state:this.state.resetPage().toggleTagRefinement(e),isPageReset:!0}),this},d.prototype.nextPage=function(){var e=this.state.page||0;return this.setPage(e+1)},d.prototype.previousPage=function(){var e=this.state.page||0;return this.setPage(e-1)},d.prototype.setCurrentPage=p,d.prototype.setPage=p,d.prototype.setIndex=function(e){return this._change({state:this.state.resetPage().setIndex(e),isPageReset:!0}),this},d.prototype.setQueryParameter=function(e,t){return this._change({state:this.state.resetPage().setQueryParameter(e,t),isPageReset:!0}),this},d.prototype.setState=function(e){return this._change({state:f.make(e),isPageReset:!1}),this},d.prototype.overrideStateWithoutTriggeringChangeEvent=function(e){return this.state=new f(e),this},d.prototype.hasRefinements=function(e){return!!u(this.state.getNumericRefinements(e))||(this.state.isConjunctiveFacet(e)?this.state.isFacetRefined(e):this.state.isDisjunctiveFacet(e)?this.state.isDisjunctiveFacetRefined(e):!!this.state.isHierarchicalFacet(e)&&this.state.isHierarchicalFacetRefined(e))},d.prototype.isExcluded=function(e,t){return this.state.isExcludeRefined(e,t)},d.prototype.isDisjunctiveRefined=function(e,t){return this.state.isDisjunctiveFacetRefined(e,t)},d.prototype.hasTag=function(e){return this.state.isTagRefined(e)},d.prototype.isTagRefined=function(){return this.hasTagRefinements.apply(this,arguments)},d.prototype.getIndex=function(){return this.state.index},d.prototype.getCurrentPage=v,d.prototype.getPage=v,d.prototype.getTags=function(){return this.state.tagRefinements},d.prototype.getRefinements=function(e){var t=[];if(this.state.isConjunctiveFacet(e))this.state.getConjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"conjunctive"})})),this.state.getExcludeRefinements(e).forEach((function(e){t.push({value:e,type:"exclude"})}));else if(this.state.isDisjunctiveFacet(e)){this.state.getDisjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"disjunctive"})}))}var r=this.state.getNumericRefinements(e);return Object.keys(r).forEach((function(e){var n=r[e];t.push({value:n,operator:e,type:"numeric"})})),t},d.prototype.getNumericRefinement=function(e,t){return this.state.getNumericRefinement(e,t)},d.prototype.getHierarchicalFacetBreadcrumb=function(e){return this.state.getHierarchicalFacetBreadcrumb(e)},d.prototype._search=function(e){var t=this.state,r=[],n=[];e.onlyWithDerivedHelpers||(n=h._getQueries(t.index,t),r.push({state:t,queriesCount:n.length,helper:this}),this.emit("search",{state:t,results:this.lastResults}));var i=this.derivedHelpers.map((function(e){var n=e.getModifiedState(t),i=n.index?h._getQueries(n.index,n):[];return r.push({state:n,queriesCount:i.length,helper:e}),e.emit("search",{state:n,results:e.lastResults}),i})),a=Array.prototype.concat.apply(n,i),s=this._queryId++;if(this._currentNbQueries++,!a.length)return Promise.resolve({results:[]}).then(this._dispatchAlgoliaResponse.bind(this,r,s));try{this.client.search(a).then(this._dispatchAlgoliaResponse.bind(this,r,s)).catch(this._dispatchAlgoliaError.bind(this,s))}catch(c){this.emit("error",{error:c})}},d.prototype._dispatchAlgoliaResponse=function(e,t,r){if(!(t0},d.prototype._change=function(e){var t=e.state,r=e.isPageReset;t!==this.state&&(this.state=t,this.emit("change",{state:this.state,results:this.lastResults,isPageReset:r}))},d.prototype.clearCache=function(){return this.client.clearCache&&this.client.clearCache(),this},d.prototype.setClient=function(e){return this.client===e||("function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+m+")"),this.client=e),this},d.prototype.getClient=function(){return this.client},d.prototype.derive=function(e){var t=new i(this,e);return this.derivedHelpers.push(t),t},d.prototype.detachDerivedHelper=function(e){var t=this.derivedHelpers.indexOf(e);if(-1===t)throw new Error("Derived helper already detached");this.derivedHelpers.splice(t,1)},d.prototype.hasPendingRequests=function(){return this._currentNbQueries>0},e.exports=d},4587:e=>{"use strict";e.exports=function(e){return Array.isArray(e)?e.filter(Boolean):[]}},2344:e=>{"use strict";e.exports=function(){return Array.prototype.slice.call(arguments).reduceRight((function(e,t){return Object.keys(Object(t)).forEach((function(r){void 0!==t[r]&&(void 0!==e[r]&&delete e[r],e[r]=t[r])})),e}),{})}},4039:e=>{"use strict";e.exports={escapeFacetValue:function(e){return"string"!=typeof e?e:String(e).replace(/^-/,"\\-")},unescapeFacetValue:function(e){return"string"!=typeof e?e:e.replace(/^\\-/,"-")}}},7888:e=>{"use strict";e.exports=function(e,t){if(Array.isArray(e))for(var r=0;r{"use strict";e.exports=function(e,t){if(!Array.isArray(e))return-1;for(var r=0;r{"use strict";var n=r(7888);e.exports=function(e,t){var r=(t||[]).map((function(e){return e.split(":")}));return e.reduce((function(e,t){var i=t.split(":"),a=n(r,(function(e){return e[0]===i[0]}));return i.length>1||!a?(e[0].push(i[0]),e[1].push(i[1]),e):(e[0].push(a[0]),e[1].push(a[1]),e)}),[[],[]])}},4853:e=>{"use strict";e.exports=function(e,t){e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}},2686:e=>{"use strict";e.exports=function(e,t){return e.filter((function(r,n){return t.indexOf(r)>-1&&e.indexOf(r)===n}))}},185:e=>{"use strict";function t(e){return"function"==typeof e||Array.isArray(e)||"[object Object]"===Object.prototype.toString.call(e)}function r(e,n){if(e===n)return e;for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)&&"__proto__"!==i&&"constructor"!==i){var a=n[i],s=e[i];void 0!==s&&void 0===a||(t(s)&&t(a)?e[i]=r(s,a):e[i]="object"==typeof(c=a)&&null!==c?r(Array.isArray(c)?[]:{},c):c)}var c;return e}e.exports=function(e){t(e)||(e={});for(var n=1,i=arguments.length;n{"use strict";e.exports=function(e){return e&&Object.keys(e).length>0}},9803:e=>{"use strict";e.exports=function(e,t){if(null===e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n=0||(i[r]=e[r]);return i}},2148:e=>{"use strict";function t(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=void 0!==t,a=null===t;if(!a&&e>t||n&&i||!r)return 1;if(!n&&e=n.length?a:"desc"===n[i]?-a:a}return e.index-r.index})),i.map((function(e){return e.value}))}},8023:e=>{"use strict";e.exports=function e(t){if("number"==typeof t)return t;if("string"==typeof t)return parseFloat(t);if(Array.isArray(t))return t.map(e);throw new Error("The value should be a number, a parsable string or an array of those.")}},6394:(e,t,r)=>{"use strict";var n=r(185);function i(e){return Object.keys(e).sort().reduce((function(t,r){return t[r]=e[r],t}),{})}var a={_getQueries:function(e,t){var r=[];return r.push({indexName:e,params:a._getHitsSearchParams(t)}),t.getRefinedDisjunctiveFacets().forEach((function(n){r.push({indexName:e,params:a._getDisjunctiveFacetSearchParams(t,n)})})),t.getRefinedHierarchicalFacets().forEach((function(n){var i=t.getHierarchicalFacetByName(n),s=t.getHierarchicalRefinement(n),c=t._getHierarchicalFacetSeparator(i);if(s.length>0&&s[0].split(c).length>1){var u=s[0].split(c).slice(0,-1).reduce((function(e,t,r){return e.concat({attribute:i.attributes[r],value:0===r?t:[e[e.length-1].value,t].join(c)})}),[]);u.forEach((function(n,s){var c=a._getDisjunctiveFacetSearchParams(t,n.attribute,0===s);function o(e){return i.attributes.some((function(t){return t===e.split(":")[0]}))}var h=(c.facetFilters||[]).reduce((function(e,t){if(Array.isArray(t)){var r=t.filter((function(e){return!o(e)}));r.length>0&&e.push(r)}return"string"!=typeof t||o(t)||e.push(t),e}),[]),f=u[s-1];c.facetFilters=s>0?h.concat(f.attribute+":"+f.value):h.length>0?h:void 0,r.push({indexName:e,params:c})}))}})),r},_getHitsSearchParams:function(e){var t=e.facets.concat(e.disjunctiveFacets).concat(a._getHitsHierarchicalFacetsAttributes(e)).sort(),r=a._getFacetFilters(e),s=a._getNumericFilters(e),c=a._getTagFilters(e),u={facets:t.indexOf("*")>-1?["*"]:t,tagFilters:c};return r.length>0&&(u.facetFilters=r),s.length>0&&(u.numericFilters=s),i(n({},e.getQueryParams(),u))},_getDisjunctiveFacetSearchParams:function(e,t,r){var s=a._getFacetFilters(e,t,r),c=a._getNumericFilters(e,t),u=a._getTagFilters(e),o={hitsPerPage:0,page:0,analytics:!1,clickAnalytics:!1};u.length>0&&(o.tagFilters=u);var h=e.getHierarchicalFacetByName(t);return o.facets=h?a._getDisjunctiveHierarchicalFacetAttribute(e,h,r):t,c.length>0&&(o.numericFilters=c),s.length>0&&(o.facetFilters=s),i(n({},e.getQueryParams(),o))},_getNumericFilters:function(e,t){if(e.numericFilters)return e.numericFilters;var r=[];return Object.keys(e.numericRefinements).forEach((function(n){var i=e.numericRefinements[n]||{};Object.keys(i).forEach((function(e){var a=i[e]||[];t!==n&&a.forEach((function(t){if(Array.isArray(t)){var i=t.map((function(t){return n+e+t}));r.push(i)}else r.push(n+e+t)}))}))})),r},_getTagFilters:function(e){return e.tagFilters?e.tagFilters:e.tagRefinements.join(",")},_getFacetFilters:function(e,t,r){var n=[],i=e.facetsRefinements||{};Object.keys(i).sort().forEach((function(e){(i[e]||[]).sort().forEach((function(t){n.push(e+":"+t)}))}));var a=e.facetsExcludes||{};Object.keys(a).sort().forEach((function(e){(a[e]||[]).sort().forEach((function(t){n.push(e+":-"+t)}))}));var s=e.disjunctiveFacetsRefinements||{};Object.keys(s).sort().forEach((function(e){var r=s[e]||[];if(e!==t&&r&&0!==r.length){var i=[];r.sort().forEach((function(t){i.push(e+":"+t)})),n.push(i)}}));var c=e.hierarchicalFacetsRefinements||{};return Object.keys(c).sort().forEach((function(i){var a=(c[i]||[])[0];if(void 0!==a){var s,u,o=e.getHierarchicalFacetByName(i),h=e._getHierarchicalFacetSeparator(o),f=e._getHierarchicalRootPath(o);if(t===i){if(-1===a.indexOf(h)||!f&&!0===r||f&&f.split(h).length===a.split(h).length)return;f?(u=f.split(h).length-1,a=f):(u=a.split(h).length-2,a=a.slice(0,a.lastIndexOf(h))),s=o.attributes[u]}else u=a.split(h).length-1,s=o.attributes[u];s&&n.push([s+":"+a])}})),n},_getHitsHierarchicalFacetsAttributes:function(e){return e.hierarchicalFacets.reduce((function(t,r){var n=e.getHierarchicalRefinement(r.name)[0];if(!n)return t.push(r.attributes[0]),t;var i=e._getHierarchicalFacetSeparator(r),a=n.split(i).length,s=r.attributes.slice(0,a+1);return t.concat(s)}),[])},_getDisjunctiveHierarchicalFacetAttribute:function(e,t,r){var n=e._getHierarchicalFacetSeparator(t);if(!0===r){var i=e._getHierarchicalRootPath(t),a=0;return i&&(a=i.split(n).length),[t.attributes[a]]}var s=(e.getHierarchicalRefinement(t.name)[0]||"").split(n).length-1;return t.attributes.slice(0,s+1)},getSearchForFacetQuery:function(e,t,r,s){var c=s.isDisjunctiveFacet(e)?s.clearRefinements(e):s,u={facetQuery:t,facetName:e};return"number"==typeof r&&(u.maxFacetHits=r),i(n({},a._getHitsSearchParams(c),u))}};e.exports=a},6801:e=>{"use strict";e.exports=function(e){return null!==e&&/^[a-zA-Z0-9_-]{1,64}$/.test(e)}},4336:e=>{"use strict";e.exports="3.15.0"},290:function(e){e.exports=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(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 r(r){for(var n=1;n=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],n=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(n=(s=c.next()).done)&&(r.push(s.value),!t||r.length!==t);n=!0);}catch(e){i=!0,a=e}finally{try{n||null==c.return||c.return()}finally{if(i)throw a}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){c();var t=JSON.stringify(e);return a()[t]})).then((function(e){return Promise.all([e?e.value:t(),void 0!==e])})).then((function(e){var t=i(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var i=a();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:t},n().setItem(r,JSON.stringify(i)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function c(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return t().then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,i).catch((function(){return c({caches:t}).get(e,n,i)}))},set:function(e,n){return r.set(e,n).catch((function(){return c({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return c({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return c({caches:t}).clear()}))}}}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var s=n(),c=i&&i.miss||function(){return Promise.resolve()};return s.then((function(e){return c(e)})).then((function(){return s}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function o(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function h(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},p=1,v=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function R(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var F="GET",b="POST";function P(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),i=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:i.length>0?i.map((function(e){return R(e)})):t}}))}function j(e,t,n,i){var s=[],c=function(e,t){if(e.method!==F&&(void 0!==e.data||void 0!==t.data)){var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}}(n,i),u=function(e,t){var n=r(r({},e.headers),t.headers),i={};return Object.keys(n).forEach((function(e){var t=n[e];i[e.toLowerCase()]=t})),i}(e,i),o=n.method,h=n.method!==F?{}:r(r({},n.data),i.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),h),i.queryParameters),l=0,m=function t(r,a){var h=r.pop();if(void 0===h)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:O(s)};var m={data:c,headers:u,method:o,url:E(h,n.path,f),connectTimeout:a(l,e.timeouts.connect),responseTimeout:a(l,i.timeout)},d=function(e){var t={request:m,response:e,host:h,triesLeft:r.length};return s.push(t),t},p={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var i=d(n);return n.isTimedOut&&l++,Promise.all([e.logger.info("Retryable failure",w(i)),e.hostsCache.set(h,y(h,n.isTimedOut?g:v))]).then((function(){return t(r,a)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,i=r;try{i=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(i,n,t)}(e,O(s))}};return e.requester.send(m).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,p)}))};return P(e.hostsCache,t).then((function(e){return m(a(e.statelessHosts).reverse(),e.getTimeout)}))}function _(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function E(e,t,r){var n=x(r),i="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(i+="?".concat(n)),i}function x(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function O(e){return e.map((function(e){return w(e)}))}function w(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var N=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===l.WithinHeaders?n:{}},queryParameters:function(){return e===l.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:l.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,s=e.responsesCache,c=e.timeouts,u=e.userAgent,o=e.hosts,h=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:s,timeouts:c,userAgent:u,headers:e.headers,queryParameters:h,hosts:o.map((function(e){return R(e)})),read:function(e,t){var r=m(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=i(e,2);return t[0],t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Write)})),e,m(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(o([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return h({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},A=function(e){return function(t,r){return t.method===F?e.transporter.read(t,r):e.transporter.write(t,r)}},H=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return h({transporter:e.transporter,appId:e.appId,indexName:t},r.methods)}},S=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{params:x(e.params||{})})}));return e.transporter.read({method:b,path:"1/indexes/*/queries",data:{requests:i},cacheable:!0},n)}},T=function(e){return function(t,i){return Promise.all(t.map((function(t){var a=t.params,s=a.facetName,c=a.facetQuery,u=n(a,["facetName","facetQuery"]);return H(e)(t.indexName,{methods:{searchForFacetValues:I}}).searchForFacetValues(s,c,r(r({},i),u))})))}},Q=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},C=function(e){return function(t,r){return e.transporter.read({method:b,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},I=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},k=1,D=2,q=3;function V(e,t,n){var i,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,i=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=i(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=i(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(i=q,{debug:function(e,t){return k>=i&&console.debug(e,t),Promise.resolve()},info:function(e,t){return D>=i&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:u(),requestsCache:u({serializable:!1}),hostsCache:c({caches:[s({key:"".concat("4.20.0","-").concat(e)}),u()]}),userAgent:_("4.20.0").add({segment:"Browser",version:"lite"}),authMode:l.WithinQueryParameters};return N(r(r(r({},a),n),{},{methods:{search:S,searchForFacetValues:T,multipleQueries:S,multipleSearchForFacetValues:T,customRequest:A,initIndex:function(e){return function(t){return H(e)(t,{methods:{search:C,searchForFacetValues:I,findAnswers:Q}})}}}}))}return V.version="4.20.0",V}()},6675:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>A});var n=r(7294),i=r(6010),a=r(8131),s=r.n(a),c=r(290),u=r.n(c),o=r(412),h=r(5742),f=r(9960),l=r(143),m=r(2263);const d=["zero","one","two","few","many","other"];function p(e){return d.filter((t=>e.includes(t)))}const v={locale:"en",pluralForms:p(["one","other"]),select:e=>1===e?"one":"other"};function g(){const{i18n:{currentLocale:e}}=(0,m.Z)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:p(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),v}}),[e])}function y(){const e=g();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const i=r.select(t),a=r.pluralForms.indexOf(i);return n[Math.min(a,n.length-1)]}(r,t,e)}}var R=r(6177),F=r(902),b=r(833),P=r(2128),j=r(5999),_=r(6278),E=r(239),x=r(7452);const O={searchQueryInput:"searchQueryInput_u2C7",searchVersionInput:"searchVersionInput_m0Ui",searchResultsColumn:"searchResultsColumn_JPFH",algoliaLogo:"algoliaLogo_rT1R",algoliaLogoPathFill:"algoliaLogoPathFill_WdUC",searchResultItem:"searchResultItem_Tv2o",searchResultItemHeading:"searchResultItemHeading_KbCB",searchResultItemPath:"searchResultItemPath_lhe1",searchResultItemSummary:"searchResultItemSummary_AEaO",searchQueryColumn:"searchQueryColumn_RTkw",searchVersionColumn:"searchVersionColumn_ypXd",searchLogoColumn:"searchLogoColumn_rJIA",loadingSpinner:"loadingSpinner_XVxU","loading-spin":"loading-spin_vzvp",loader:"loader_vvXV"};function w(e){let{docsSearchVersionsHelpers:t}=e;const r=Object.entries(t.allDocsData).filter((e=>{let[,t]=e;return t.versions.length>1}));return n.createElement("div",{className:(0,i.Z)("col","col--3","padding-left--none",O.searchVersionColumn)},r.map((e=>{let[i,a]=e;const s=r.length>1?`${i}: `:"";return n.createElement("select",{key:i,onChange:e=>t.setSearchVersion(i,e.target.value),defaultValue:t.searchVersions[i],className:O.searchVersionInput},a.versions.map(((e,t)=>n.createElement("option",{key:t,label:`${s}${e.label}`,value:e.name}))))})))}function N(){const{i18n:{currentLocale:e}}=(0,m.Z)(),{algolia:{appId:t,apiKey:r,indexName:a}}=(0,_.L)(),c=(0,E.l)(),d=function(){const{selectMessage:e}=y();return t=>e(t,(0,j.I)({id:"theme.SearchPage.documentsFound.plurals",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One document found|{count} documents found"},{count:t}))}(),p=function(){const e=(0,l._r)(),[t,r]=(0,n.useState)((()=>Object.entries(e).reduce(((e,t)=>{let[r,n]=t;return{...e,[r]:n.versions[0].name}}),{}))),i=Object.values(e).some((e=>e.versions.length>1));return{allDocsData:e,versioningEnabled:i,searchVersions:t,setSearchVersion:(e,t)=>r((r=>({...r,[e]:t})))}}(),[v,g]=(0,R.K)(),b={items:[],query:null,totalResults:null,totalPages:null,lastPage:null,hasMore:null,loading:null},[N,A]=(0,n.useReducer)(((e,t)=>{switch(t.type){case"reset":return b;case"loading":return{...e,loading:!0};case"update":return v!==t.value.query?e:{...t.value,items:0===t.value.lastPage?t.value.items:e.items.concat(t.value.items)};case"advance":{const t=e.totalPages>e.lastPage+1;return{...e,lastPage:t?e.lastPage+1:e.lastPage,hasMore:t}}default:return e}}),b),H=u()(t,r),S=s()(H,a,{hitsPerPage:15,advancedSyntax:!0,disjunctiveFacets:["language","docusaurus_tag"]});S.on("result",(e=>{let{results:{query:t,hits:r,page:n,nbHits:i,nbPages:a}}=e;if(""===t||!Array.isArray(r))return void A({type:"reset"});const s=e=>e.replace(/algolia-docsearch-suggestion--highlight/g,"search-result-match"),u=r.map((e=>{let{url:t,_highlightResult:{hierarchy:r},_snippetResult:n={}}=e;const i=Object.keys(r).map((e=>s(r[e].value)));return{title:i.pop(),url:c(t),summary:n.content?`${s(n.content.value)}...`:"",breadcrumbs:i}}));A({type:"update",value:{items:u,query:t,totalResults:i,totalPages:a,lastPage:n,hasMore:a>n+1,loading:!1}})}));const[T,Q]=(0,n.useState)(null),C=(0,n.useRef)(0),I=(0,n.useRef)(o.Z.canUseIntersectionObserver&&new IntersectionObserver((e=>{const{isIntersecting:t,boundingClientRect:{y:r}}=e[0];t&&C.current>r&&A({type:"advance"}),C.current=r}),{threshold:1})),k=()=>v?(0,j.I)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:v}):(0,j.I)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"}),D=(0,F.zX)((function(t){void 0===t&&(t=0),S.addDisjunctiveFacetRefinement("docusaurus_tag","default"),S.addDisjunctiveFacetRefinement("language",e),Object.entries(p.searchVersions).forEach((e=>{let[t,r]=e;S.addDisjunctiveFacetRefinement("docusaurus_tag",`docs-${t}-${r}`)})),S.setQuery(v).setPage(t).search()}));return(0,n.useEffect)((()=>{if(!T)return;const e=I.current;return e?(e.observe(T),()=>e.unobserve(T)):()=>!0}),[T]),(0,n.useEffect)((()=>{A({type:"reset"}),v&&(A({type:"loading"}),setTimeout((()=>{D()}),300))}),[v,p.searchVersions,D]),(0,n.useEffect)((()=>{N.lastPage&&0!==N.lastPage&&D(N.lastPage)}),[D,N.lastPage]),n.createElement(x.Z,null,n.createElement(h.Z,null,n.createElement("title",null,(0,P.p)(k())),n.createElement("meta",{property:"robots",content:"noindex, follow"})),n.createElement("div",{className:"container margin-vert--lg"},n.createElement("h1",null,k()),n.createElement("form",{className:"row",onSubmit:e=>e.preventDefault()},n.createElement("div",{className:(0,i.Z)("col",O.searchQueryColumn,{"col--9":p.versioningEnabled,"col--12":!p.versioningEnabled})},n.createElement("input",{type:"search",name:"q",className:O.searchQueryInput,placeholder:(0,j.I)({id:"theme.SearchPage.inputPlaceholder",message:"Type your search here",description:"The placeholder for search page input"}),"aria-label":(0,j.I)({id:"theme.SearchPage.inputLabel",message:"Search",description:"The ARIA label for search page input"}),onChange:e=>g(e.target.value),value:v,autoComplete:"off",autoFocus:!0})),p.versioningEnabled&&n.createElement(w,{docsSearchVersionsHelpers:p})),n.createElement("div",{className:"row"},n.createElement("div",{className:(0,i.Z)("col","col--8",O.searchResultsColumn)},!!N.totalResults&&d(N.totalResults)),n.createElement("div",{className:(0,i.Z)("col","col--4","text--right",O.searchLogoColumn)},n.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://www.algolia.com/","aria-label":(0,j.I)({id:"theme.SearchPage.algoliaLabel",message:"Search by Algolia",description:"The ARIA label for Algolia mention"})},n.createElement("svg",{viewBox:"0 0 168 24",className:O.algoliaLogo},n.createElement("g",{fill:"none"},n.createElement("path",{className:O.algoliaLogoPathFill,d:"M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"}),n.createElement("path",{fill:"#5468FF",d:"M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"}),n.createElement("path",{fill:"white",d:"M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"})))))),N.items.length>0?n.createElement("main",null,N.items.map(((e,t)=>{let{title:r,url:a,summary:s,breadcrumbs:c}=e;return n.createElement("article",{key:t,className:O.searchResultItem},n.createElement("h2",{className:O.searchResultItemHeading},n.createElement(f.Z,{to:a,dangerouslySetInnerHTML:{__html:r}})),c.length>0&&n.createElement("nav",{"aria-label":"breadcrumbs"},n.createElement("ul",{className:(0,i.Z)("breadcrumbs",O.searchResultItemPath)},c.map(((e,t)=>n.createElement("li",{key:t,className:"breadcrumbs__item",dangerouslySetInnerHTML:{__html:e}}))))),s&&n.createElement("p",{className:O.searchResultItemSummary,dangerouslySetInnerHTML:{__html:s}}))}))):[v&&!N.loading&&n.createElement("p",{key:"no-results"},n.createElement(j.Z,{id:"theme.SearchPage.noResultsText",description:"The paragraph for empty search result"},"No results were found")),!!N.loading&&n.createElement("div",{key:"spinner",className:O.loadingSpinner})],N.hasMore&&n.createElement("div",{className:O.loader,ref:Q},n.createElement(j.Z,{id:"theme.SearchPage.fetchingNewResults",description:"The paragraph for fetching new search results"},"Fetching new results..."))))}function A(){return n.createElement(b.FG,{className:"search-page-wrapper"},n.createElement(N,null))}}}]); \ No newline at end of file diff --git a/assets/js/1a4e3797.dd8146f2.js.LICENSE.txt b/assets/js/1a4e3797.dd8146f2.js.LICENSE.txt new file mode 100644 index 000000000000..8c17e740e697 --- /dev/null +++ b/assets/js/1a4e3797.dd8146f2.js.LICENSE.txt @@ -0,0 +1 @@ +/*! algoliasearch-lite.umd.js | 4.20.0 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */ diff --git a/assets/js/1be78505.dc6e92dc.js b/assets/js/1be78505.dc6e92dc.js new file mode 100644 index 000000000000..03b1e5894e38 --- /dev/null +++ b/assets/js/1be78505.dc6e92dc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[9514,4972],{9963:(e,t,n)=>{n.r(t),n.d(t,{default:()=>fe});var a=n(7294),l=n(6010),o=n(833),r=n(5281),c=n(3320),i=n(2802),s=n(4477),d=n(1116),m=n(7452),u=n(5999),b=n(2466),p=n(5936);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,l]=(0,a.useState)(!1),o=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.Ct)();return(0,b.RF)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(o.current?o.current=!1:a>=r?(c(),l(!1)):a{e.location.hash&&(o.current=!0,l(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,l.Z)("clean-btn",r.k.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(6550),g=n(7524),v=n(6668),_=n(1327),k=n(7462);function C(e){return a.createElement("svg",(0,k.Z)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const S={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function I(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,l.Z)("button button--secondary button--outline",S.collapseSidebarButton),onClick:t},a.createElement(C,{className:S.collapseSidebarButtonIcon}))}var N=n(9689),T=n(902);const x=Symbol("EmptyContext"),Z=a.createContext(x);function B(e){let{children:t}=e;const[n,l]=(0,a.useState)(null),o=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:l})),[n]);return a.createElement(Z.Provider,{value:o},t)}var y=n(6043),w=n(8596),L=n(9960),A=n(2389);function M(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function F(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,v.L)(),f=function(e){const t=(0,A.Z)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i.Wl)(e):void 0),[e,t])}(t),g=(0,i._F)(t,o),_=(0,w.Mg)(h,o),{collapsed:C,setCollapsed:S}=(0,y.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:I,setExpandedItem:N}=function(){const e=(0,a.useContext)(Z);if(e===x)throw new T.i6("DocSidebarItemsExpandedStateProvider");return e}(),B=function(e){void 0===e&&(e=!C),N(e?null:s),S(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:l}=e;const o=(0,T.D9)(t);(0,a.useEffect)((()=>{t&&!o&&n&&l(!1)}),[t,o,n,l])}({isActive:g,collapsed:C,updateCollapsed:B}),(0,a.useEffect)((()=>{b&&null!=I&&I!==s&&E&&S(!0)}),[b,I,s,S,E]),a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemCategory,r.k.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":C},p)},a.createElement("div",{className:(0,l.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":_})},a.createElement(L.Z,(0,k.Z)({className:(0,l.Z)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?B(!1):(e.preventDefault(),B())}:()=>{n?.(t)},"aria-current":_?"page":void 0,"aria-expanded":b?!C:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(M,{categoryLabel:u,onClick:e=>{e.preventDefault(),B()}})),a.createElement(y.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:C},a.createElement(K,{items:m,tabIndex:C?-1:0,onItemClick:n,activePath:o,level:c+1})))}var H=n(3919),P=n(9471);const W={menuExternalLink:"menuExternalLink_NmtK"};function D(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i._F)(t,o),E=(0,H.Z)(m);return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(L.Z,(0,k.Z)({className:(0,l.Z)("menu__link",!E&&W.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(P.Z,null)))}const R={menuHtmlItem:"menuHtmlItem_M9Kj"};function V(e){let{item:t,level:n,index:o}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(n),i&&[R.menuHtmlItem,"menu__list-item"],s),key:o,dangerouslySetInnerHTML:{__html:c}})}function z(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(F,(0,k.Z)({item:t},n));case"html":return a.createElement(V,(0,k.Z)({item:t},n));default:return a.createElement(D,(0,k.Z)({item:t},n))}}function U(e){let{items:t,...n}=e;return a.createElement(B,null,t.map(((e,t)=>a.createElement(z,(0,k.Z)({key:t,item:e,index:t},n)))))}const K=(0,a.memo)(U),j={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function q(e){let{path:t,sidebar:n,className:o}=e;const c=function(){const{isActive:e}=(0,N.nT)(),[t,n]=(0,a.useState)(e);return(0,b.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{"aria-label":(0,u.I)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,l.Z)("menu thin-scrollbar",j.menu,c&&j.menuWithAnnouncementBar,o)},a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:n,activePath:t,level:1})))}const G="sidebar_njMd",Y="sidebarWithHideableNavbar_wUlq",O="sidebarHidden_VK0M",X="sidebarLogo_isFc";function J(e){let{path:t,sidebar:n,onCollapse:o,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,v.L)();return a.createElement("div",{className:(0,l.Z)(G,c&&Y,r&&O)},c&&a.createElement(_.Z,{tabIndex:-1,className:X}),a.createElement(q,{path:t,sidebar:n}),i&&a.createElement(I,{onClick:o}))}const Q=a.memo(J);var $=n(3102),ee=n(3163);const te=e=>{let{sidebar:t,path:n}=e;const o=(0,ee.e)();return a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&o.toggle(),"link"===e.type&&o.toggle()},level:1}))};function ne(e){return a.createElement($.Zo,{component:te,props:e})}const ae=a.memo(ne);function le(e){const t=(0,g.i)(),n="desktop"===t||"ssr"===t,l="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(Q,e),l&&a.createElement(ae,e))}const oe={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function re(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:oe.expandButton,title:(0,u.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(C,{className:oe.expandButtonIcon}))}const ce={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry",sidebarViewport:"sidebarViewport_Xe31"};function ie(e){let{children:t}=e;const n=(0,d.V)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function se(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:o}=e;const{pathname:c}=(0,f.TH)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),o((e=>!e))}),[o,i]);return a.createElement("aside",{className:(0,l.Z)(r.k.docs.docSidebarContainer,ce.docSidebarContainer,n&&ce.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ce.docSidebarContainer)&&n&&s(!0)}},a.createElement(ie,null,a.createElement("div",{className:(0,l.Z)(ce.sidebarViewport,i&&ce.sidebarViewportHidden)},a.createElement(le,{sidebar:t,path:c,onCollapse:d,isHidden:i}),i&&a.createElement(re,{toggleSidebar:d}))))}const de={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function me(e){let{hiddenSidebarContainer:t,children:n}=e;const o=(0,d.V)();return a.createElement("main",{className:(0,l.Z)(de.docMainContainer,(t||!o)&&de.docMainContainerEnhanced)},a.createElement("div",{className:(0,l.Z)("container padding-top--md padding-bottom--lg",de.docItemWrapper,t&&de.docItemWrapperEnhanced)},n))}const ue={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX"};function be(e){let{children:t}=e;const n=(0,d.V)(),[l,o]=(0,a.useState)(!1);return a.createElement(m.Z,{wrapperClassName:ue.docsWrapper},a.createElement(E,null),a.createElement("div",{className:ue.docPage},n&&a.createElement(se,{sidebar:n.items,hiddenSidebarContainer:l,setHiddenSidebarContainer:o}),a.createElement(me,{hiddenSidebarContainer:l},t)))}var pe=n(4972),he=n(197);function Ee(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(he.Z,{version:t.version,tag:(0,c.os)(t.pluginId,t.version)}),a.createElement(o.d,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function fe(e){const{versionMetadata:t}=e,n=(0,i.hI)(e);if(!n)return a.createElement(pe.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(Ee,e),a.createElement(o.FG,{className:(0,l.Z)(r.k.wrapper.docsPages,r.k.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.q,{version:t},a.createElement(d.b,{name:m,items:u},a.createElement(be,null,c)))))}},4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(7294),l=n(5999),o=n(833),r=n(7452);function c(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>c,q:()=>r});var a=n(7294),l=n(902);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/1df93b7f.7f8f9032.js b/assets/js/1df93b7f.7f8f9032.js new file mode 100644 index 000000000000..39449cce25fe --- /dev/null +++ b/assets/js/1df93b7f.7f8f9032.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3237],{3808:(e,t,a)=>{a.r(t),a.d(t,{default:()=>g});var r=a(7462),n=a(9960),l=a(4996),s=a(2263),c=a(7452),i=a(6010),o=a(7294);const m={heroBanner:"heroBanner_qdFl",buttons:"buttons_AeoN",features:"features_cAfv",featureImage:"featureImage_wMIZ","hero--primary":"hero--primary_JQ01",button:"button_JGCe"},u=[{title:"Ethereal Engine Embraces The Web",imageUrl:"img/undraw_docusaurus_mountain.svg",description:o.createElement(o.Fragment,null,"Reach everyone. No app stores. Open Source. ",o.createElement("br",null),"Mobile - Desktop - Headsets")},{title:"Focus On What Matters",imageUrl:"img/undraw_docusaurus_tree.svg",description:o.createElement(o.Fragment,null,"A comprehensive studio, pipeline tools, endless immersive features.")},{title:"Built On Well Known Web Frameworks",imageUrl:"img/undraw_docusaurus_react.svg",description:o.createElement(o.Fragment,null,"Power your experiences immediately with React, Threejs, Feathers, Kubernetes, bitECS")}];function d(e){let{imageUrl:t,title:a,description:r}=e;const n=(0,l.Z)(t);return o.createElement("div",{className:(0,i.Z)("col col--4",m.feature)},n&&o.createElement("div",{className:"text--center"},o.createElement("img",{className:m.featureImage,src:n,alt:a})),o.createElement("h3",null,a),o.createElement("p",null,r))}function g(){const{siteConfig:e}=(0,s.Z)();return o.createElement(c.Z,{title:`${e.title}`,description:"Description will go into a meta tag in "},o.createElement("header",{className:(0,i.Z)("hero hero--primary",m.heroBanner)},o.createElement("div",{className:"container"},o.createElement("h1",{className:"hero__title"},e.title),o.createElement("p",{className:"hero__subtitle"},e.tagline),o.createElement("div",{className:m.buttons},o.createElement(n.Z,{className:(0,i.Z)("button button--outline button--secondary button--lg",m.getStarted),to:(0,l.Z)("docs/")},"Get Started")))),o.createElement("main",null,u&&u.length>0&&o.createElement("section",{className:m.features},o.createElement("div",{className:"container"},o.createElement("div",{className:"row"},u.map(((e,t)=>o.createElement(d,(0,r.Z)({key:t},e)))))))))}}}]); \ No newline at end of file diff --git a/assets/js/1f391b9e.75a9ca1a.js b/assets/js/1f391b9e.75a9ca1a.js new file mode 100644 index 000000000000..8c15df347a0b --- /dev/null +++ b/assets/js/1f391b9e.75a9ca1a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3085],{4247:(e,t,a)=>{a.r(t),a.d(t,{default:()=>d});var l=a(7294),n=a(6010),c=a(833),r=a(5281),m=a(7452),i=a(7432),s=a(9407);const o={mdxPageWrapper:"mdxPageWrapper_j9I6"};function d(e){const{content:t}=e,{metadata:{title:a,description:d,frontMatter:p}}=t,{wrapperClassName:g,hide_table_of_contents:_}=p;return l.createElement(c.FG,{className:(0,n.Z)(g??r.k.wrapper.mdxPages,r.k.page.mdxPage)},l.createElement(c.d,{title:a,description:d}),l.createElement(m.Z,null,l.createElement("main",{className:"container container--fluid margin-vert--lg"},l.createElement("div",{className:(0,n.Z)("row",o.mdxPageWrapper)},l.createElement("div",{className:(0,n.Z)("col",!_&&"col--8")},l.createElement("article",null,l.createElement(i.Z,null,l.createElement(t,null)))),!_&&t.toc.length>0&&l.createElement("div",{className:"col col--2"},l.createElement(s.Z,{toc:t.toc,minHeadingLevel:p.toc_min_heading_level,maxHeadingLevel:p.toc_max_heading_level}))))))}}}]); \ No newline at end of file diff --git a/assets/js/222ee964.1c0e3f8c.js b/assets/js/222ee964.1c0e3f8c.js new file mode 100644 index 000000000000..b0feebbf20be --- /dev/null +++ b/assets/js/222ee964.1c0e3f8c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[401],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/24869598.a0fec5ff.js b/assets/js/24869598.a0fec5ff.js new file mode 100644 index 000000000000..e3df39cd3aed --- /dev/null +++ b/assets/js/24869598.a0fec5ff.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3573],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>u});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 l(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 p=r.createContext({}),h=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},s=function(e){var t=h(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=h(n),c=a,u=m["".concat(p,".").concat(c)]||m[c]||d[c]||i;return n?r.createElement(u,l(l({ref:t},s),{},{components:n})):r.createElement(u,l({ref:t},s))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:a,l[1]=o;for(var h=2;h{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>o,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const i={},l="Release Helm Chart",o={unversionedId:"host/devops_deployment/release_helm_chart",id:"host/devops_deployment/release_helm_chart",title:"Release Helm Chart",description:"Following are the steps that needs to be taken in order to update etherealengine helm charts repo:",source:"@site/docs/1_host/2_devops_deployment/6_release_helm_chart.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/release_helm_chart",permalink:"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/6_release_helm_chart.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Cluster Management",permalink:"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes"},next:{title:"Upgrading Helm Release",permalink:"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment"}},p={},h=[],s={toc:h},m="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"release-helm-chart"},"Release Helm Chart"),(0,a.kt)("p",null,"Following are the steps that needs to be taken in order to update etherealengine helm charts repo:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Have a checked-out copy of ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/EtherealEngine/ethereal-engine-helm"},"https://github.com/EtherealEngine/ethereal-engine-helm"),", set to the ",(0,a.kt)("inlineCode",{parentName:"li"},"gh-pages")," branch"),(0,a.kt)("li",{parentName:"ul"},"Have a checked-out copy of ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"https://github.com/EtherealEngine/ethereal-engine-ops"),", set to the ",(0,a.kt)("inlineCode",{parentName:"li"},"master")," branch"),(0,a.kt)("li",{parentName:"ul"},"Set working directory to local ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-ops")," folder"),(0,a.kt)("li",{parentName:"ul"},"Increase the version number in ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine/Chart.yaml")),(0,a.kt)("li",{parentName:"ul"},"Run ",(0,a.kt)("inlineCode",{parentName:"li"},"helm package etherealengine")),(0,a.kt)("li",{parentName:"ul"},"Run ",(0,a.kt)("inlineCode",{parentName:"li"},"helm repo index --url https://helm.etherealengine.org .")),(0,a.kt)("li",{parentName:"ul"},"Copy ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine-X.Y.Z.tgz")," that's generated to the root of the ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm")," repo, and make sure to ",(0,a.kt)("inlineCode",{parentName:"li"},"git add")," it."),(0,a.kt)("li",{parentName:"ul"},"Open ",(0,a.kt)("inlineCode",{parentName:"li"},"index.yaml"),". Under entries.xrengine, there should be an entry for the new version."),(0,a.kt)("li",{parentName:"ul"},"Copy that entry to ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm"),"'s ",(0,a.kt)("inlineCode",{parentName:"li"},"index.yaml"),", making sure to put it under the right ",(0,a.kt)("inlineCode",{parentName:"li"},"entries")," section; we've got ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine-builder")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine")," in the same file, so pay attention to which one you're putting it in. Also make sure that the spacing/indentation matches the other entries."),(0,a.kt)("li",{parentName:"ul"},"Copy the ",(0,a.kt)("inlineCode",{parentName:"li"},"generated")," line from ",(0,a.kt)("inlineCode",{parentName:"li"},"index.yaml")," to ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm/index.yaml"),", overwriting the ",(0,a.kt)("inlineCode",{parentName:"li"},"generated")," line that's there."),(0,a.kt)("li",{parentName:"ul"},"Commit this, and push it to the ",(0,a.kt)("inlineCode",{parentName:"li"},"gh-pages")," branch of ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm"),". Within a couple of minutes, you should see the new version appear at ",(0,a.kt)("a",{parentName:"li",href:"https://helm.etherealengine.org/"},"https://helm.etherealengine.org/"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/271238cb.1d53c9db.js b/assets/js/271238cb.1d53c9db.js new file mode 100644 index 000000000000..e13dc216c355 --- /dev/null +++ b/assets/js/271238cb.1d53c9db.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5003],{3905:(e,t,n)=>{n.d(t,{Zo:()=>g,kt:()=>m});var r=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 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||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},g=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,g=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=o,m=d["".concat(c,".").concat(u)]||d[u]||p[u]||i;return n?r.createElement(m,a(a({ref:t},g),{},{components:n})):r.createElement(m,a({ref:t},g))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:o,a[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={hide_table_of_contents:!0},a="Debugging Engine in WSL on Phone/Headset",s={unversionedId:"creator/testing/debugging_device_wsl",id:"creator/testing/debugging_device_wsl",title:"Debugging Engine in WSL on Phone/Headset",description:"This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11.",source:"@site/docs/2_creator/6_testing/5_debugging_device_wsl.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/debugging_device_wsl",permalink:"/etherealengine-docs/docs/creator/testing/debugging_device_wsl",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/5_debugging_device_wsl.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Debugging",permalink:"/etherealengine-docs/docs/creator/testing/debugging"},next:{title:"Debugging Deployed Instanceservers (and other Kubernetes pods)",permalink:"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers"}},c={},l=[],g={toc:l},d="wrapper";function p(e){let{components:t,...i}=e;return(0,o.kt)(d,(0,r.Z)({},g,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"debugging-engine-in-wsl-on-phoneheadset"},"Debugging Engine in WSL on Phone/Headset"),(0,o.kt)("p",null,"This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Ensure that your ",(0,o.kt)("inlineCode",{parentName:"p"},".env.local")," and database entries points to ",(0,o.kt)("inlineCode",{parentName:"p"},"localhost"),".")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Open a location i.e. ",(0,o.kt)("inlineCode",{parentName:"p"},"https://localhost:3000/location/apartment")," through Windows 11 chrome. It should work fine.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Connect your device (currently tested on Samsung S22 Ultra) with PC and enabled USB debugging and access prompts as mentioned on ",(0,o.kt)("a",{parentName:"p",href:"https://developer.chrome.com/docs/devtools/remote-debugging/"},"https://developer.chrome.com/docs/devtools/remote-debugging/"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Once your device is connected, then you can see your device's browser tabs in PC's Chrome as show in below image. ",(0,o.kt)("inlineCode",{parentName:"p"},"chrome://inspect/#devices"),"\n",(0,o.kt)("img",{alt:"Device connected to PC Chrome",src:n(1086).Z,width:"1166",height:"540"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Make sure the check boxes marked in below are checked.\n",(0,o.kt)("img",{alt:"Remote Devtool Options",src:n(4021).Z,width:"865",height:"473"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},'Click on "Port forwarding" button and ensure you have entries as shown in below image. Also make sure to check the port forwarding checkbox in that modal.\n',(0,o.kt)("img",{alt:"Port Forwarding Options",src:n(7615).Z,width:"522",height:"444"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Once this is done and you have Port forwardings having green circles before them which means forwarding is working as shown in below image.\n",(0,o.kt)("img",{alt:"Port Forwarding Enabled",src:n(6253).Z,width:"1092",height:"504"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Navigate to ",(0,o.kt)("inlineCode",{parentName:"p"},"https://localhost:3000/location/apartment")," in your device's browser.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"On your PC you can inspect this and allow if you face any certificate errors as shown in below image.\n",(0,o.kt)("img",{alt:"Remote Debugging",src:n(9764).Z,width:"1919",height:"1033"})))))}p.isMDXComponent=!0},1086:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png"},4021:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png"},7615:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png"},6253:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png"},9764:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png"}}]); \ No newline at end of file diff --git a/assets/js/272.9b1a0f8c.js b/assets/js/272.9b1a0f8c.js new file mode 100644 index 000000000000..45fbb0e4a2c3 --- /dev/null +++ b/assets/js/272.9b1a0f8c.js @@ -0,0 +1 @@ +(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[272],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>u,kt:()=>f});var o=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 a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},p=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),p=r,f=m["".concat(i,".").concat(p)]||m[p]||d[p]||a;return n?o.createElement(f,c(c({ref:t},u),{},{components:n})):o.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=p;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[m]="string"==typeof e?e:r,c[1]=l;for(var s=2;s{"use strict";n.d(t,{Z:()=>u});var o=n(7462),r=n(7294),a=n(6010),c=n(5999),l=n(6668),i=n(9960);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function u(e){let{as:t,id:n,...u}=e;const{navbar:{hideOnScroll:m}}=(0,l.L)();if("h1"===t||!n)return r.createElement(t,(0,o.Z)({},u,{id:void 0}));const d=(0,c.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof u.children?u.children:n});return r.createElement(t,(0,o.Z)({},u,{className:(0,a.Z)("anchor",m?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,u.className),id:n}),u.children,r.createElement(i.Z,{className:"hash-link",to:`#${n}`,"aria-label":d,title:d},"\u200b"))}},7432:(e,t,n)=>{"use strict";n.d(t,{Z:()=>pe});var o=n(7294),r=n(3905),a=n(7462),c=n(5742);var l=n(2389),i=n(6010),s=n(2949),u=n(6668);function m(){const{prism:e}=(0,u.L)(),{colorMode:t}=(0,s.I)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var d=n(5281),p=n(7594),f=n.n(p);const h=/title=(?["'])(?.*?)\1/,g=/\{(?<range>[\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function v(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function b(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:r,metastring:a}=t;if(a&&g.test(a)){const e=a.match(g).groups.range;if(0===r.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${a}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=r[0].className,o=f()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return v(["js","jsBlock"],t);case"jsx":case"tsx":return v(["js","jsBlock","jsx"],t);case"html":return v(["js","jsBlock","html"],t);case"python":case"py":case"bash":return v(["bash"],t);case"markdown":case"md":return v(["html","jsx","bash"],t);default:return v(Object.keys(y),t)}}(o,r),l=n.split("\n"),i=Object.fromEntries(r.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(r.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(r.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(r.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p<l.length;){const e=l[p].match(c);if(!e){p+=1;continue}const t=e.slice(1).find((e=>void 0!==e));s[t]?i[s[t]].range+=`${p},`:u[t]?i[u[t]].start=p:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${p-1},`),l.splice(p,1)}n=l.join("\n");const d={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;f()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const E={codeBlockContainer:"codeBlockContainer_Ckt0"};function k(e){let{as:t,...n}=e;const r=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,r]=e;const a=t[o];a&&"string"==typeof r&&(n[a]=r)})),n}(m());return o.createElement(t,(0,a.Z)({},n,{style:r,className:(0,i.Z)(n.className,E.codeBlockContainer,d.k.common.codeBlock)}))}const N={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function C(e){let{children:t,className:n}=e;return o.createElement(k,{as:"pre",tabIndex:0,className:(0,i.Z)(N.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:N.codeBlockLines},t))}var L=n(902);const w={attributes:!0,characterData:!0,childList:!0,subtree:!0};function B(e,t){const[n,r]=(0,o.useState)(),a=(0,o.useCallback)((()=>{r(e.current?.closest("[role=tabpanel][hidden]"))}),[e,r]);(0,o.useEffect)((()=>{a()}),[a]),function(e,t,n){void 0===n&&(n=w);const r=(0,L.zX)(t),a=(0,L.Ql)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(r);return e&&t.observe(e,a),()=>t.disconnect()}),[e,r,a])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),a())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const x={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var T={Prism:n(7410).Z,theme:x};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 Z(){return Z=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},Z.apply(this,arguments)}var j=/\r\n|\r|\n/,_=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},H=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)};function S(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var A=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),O(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),r=e.styles.reduce((function(e,n){var o=n.languages,r=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=Z({},e[t],r);e[t]=n})),e}),o);return r.root=n,r.plain=Z({},n,{backgroundColor:null}),r}(e.theme,e.language):void 0;return t.themeDict=n})),O(this,"getLineProps",(function(e){var n=e.key,o=e.className,r=e.style,a=Z({},S(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),c=t.getThemeDict(t.props);return void 0!==c&&(a.style=c.plain),void 0!==r&&(a.style=void 0!==a.style?Z({},a.style,r):r),void 0!==n&&(a.key=n),o&&(a.className+=" "+o),a})),O(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,r=n.length,a=t.getThemeDict(t.props);if(void 0!==a){if(1===r&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===r&&!o)return a[n[0]];var c=o?{display:"inline-block"}:{},l=n.map((function(e){return a[e]}));return Object.assign.apply(Object,[c].concat(l))}})),O(this,"getTokenProps",(function(e){var n=e.key,o=e.className,r=e.style,a=e.token,c=Z({},S(e,["key","className","style","token"]),{className:"token "+a.types.join(" "),children:a.content,style:t.getStyleForToken(a),key:void 0});return void 0!==r&&(c.style=void 0!==c.style?Z({},c.style,r):r),void 0!==n&&(c.key=n),o&&(c.className+=" "+o),c})),O(this,"tokenize",(function(e,t,n,o){var r={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",r);var a=r.tokens=e.tokenize(r.code,r.grammar,r.language);return e.hooks.run("after-tokenize",r),a}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,r=e.children,a=this.getThemeDict(this.props),c=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],o=[0],r=[e.length],a=0,c=0,l=[],i=[l];c>-1;){for(;(a=o[c]++)<r[c];){var s=void 0,u=t[c],m=n[c][a];if("string"==typeof m?(u=c>0?u:["plain"],s=m):(u=H(u,m.type),m.alias&&(u=H(u,m.alias)),s=m.content),"string"==typeof s){var d=s.split(j),p=d.length;l.push({types:u,content:d[0]});for(var f=1;f<p;f++)_(l),i.push(l=[]),l.push({types:u,content:d[f]})}else c++,t.push(u),n.push(s),o.push(0),r.push(s.length)}c--,t.pop(),n.pop(),o.pop(),r.pop()}return _(l),i}(void 0!==c?this.tokenize(t,o,c,n):[o]),className:"prism-code language-"+n,style:void 0!==a?a.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(o.Component);const I=A,P={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function z(e){let{line:t,classNames:n,showLineNumbers:r,getLineProps:c,getTokenProps:l}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const s=c({line:t,className:(0,i.Z)(n,r&&P.codeLine)}),u=t.map(((e,t)=>o.createElement("span",(0,a.Z)({key:t},l({token:e,key:t})))));return o.createElement("span",s,r?o.createElement(o.Fragment,null,o.createElement("span",{className:P.codeLineNumber}),o.createElement("span",{className:P.codeLineContent},u)):u,o.createElement("br",null))}var M=n(5999);const D={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function W(e){let{code:t,className:n}=e;const[r,a]=(0,o.useState)(!1),c=(0,o.useRef)(void 0),l=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const o=document.createElement("textarea"),r=document.activeElement;o.value=e,o.setAttribute("readonly",""),o.style.contain="strict",o.style.position="absolute",o.style.left="-9999px",o.style.fontSize="12pt";const a=document.getSelection(),c=a.rangeCount>0&&a.getRangeAt(0);n.append(o),o.select(),o.selectionStart=0,o.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}o.remove(),c&&(a.removeAllRanges(),a.addRange(c)),r&&r.focus()}(t),a(!0),c.current=window.setTimeout((()=>{a(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),o.createElement("button",{type:"button","aria-label":r?(0,M.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,M.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,M.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.Z)("clean-btn",n,D.copyButton,r&&D.copyButtonCopied),onClick:l},o.createElement("span",{className:D.copyButtonIcons,"aria-hidden":"true"},o.createElement("svg",{className:D.copyButtonIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),o.createElement("svg",{className:D.copyButtonSuccessIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const R={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function V(e){let{className:t,onClick:n,isEnabled:r}=e;const a=(0,M.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,i.Z)("clean-btn",t,r&&R.wordWrapButtonEnabled),"aria-label":a,title:a},o.createElement("svg",{className:R.wordWrapButtonIcon,viewBox:"0 0 24 24","aria-hidden":"true"},o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function $(e){let{children:t,className:n="",metastring:r,title:c,showLineNumbers:l,language:s}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,u.L)(),f=s??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,g=m(),y=function(){const[e,t]=(0,o.useState)(!1),[n,r]=(0,o.useState)(!1),a=(0,o.useRef)(null),c=(0,o.useCallback)((()=>{const n=a.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[a,e]),l=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=a.current,n=e>t||a.current.querySelector("code").hasAttribute("style");r(n)}),[a]);return B(a,l),(0,o.useEffect)((()=>{l()}),[e,l]),(0,o.useEffect)((()=>(window.addEventListener("resize",l,{passive:!0}),()=>{window.removeEventListener("resize",l)})),[l]),{codeBlockRef:a,isEnabled:e,isCodeScrollable:n,toggle:c}}(),v=function(e){return e?.match(h)?.groups.title??""}(r)||c,{lineClassNames:E,code:C}=b(t,{metastring:r,language:f,magicComments:p}),L=l??function(e){return Boolean(e?.includes("showLineNumbers"))}(r);return o.createElement(k,{as:"div",className:(0,i.Z)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},v&&o.createElement("div",{className:N.codeBlockTitle},v),o.createElement("div",{className:N.codeBlockContent},o.createElement(I,(0,a.Z)({},T,{theme:g,code:C,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:r,getTokenProps:a}=e;return o.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,i.Z)(t,N.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,i.Z)(N.codeBlockLines,L&&N.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(z,{key:t,line:e,getLineProps:r,getTokenProps:a,classNames:E[t],showLineNumbers:L})))))})),o.createElement("div",{className:N.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&o.createElement(V,{className:N.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),o.createElement(W,{className:N.codeButton,code:C}))))}function q(e){let{children:t,...n}=e;const r=(0,l.Z)(),c=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof c?$:C;return o.createElement(i,(0,a.Z)({key:String(r)},n),c)}var F=n(9960);var U=n(6043);const G={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function Y(e){return!!e&&("SUMMARY"===e.tagName||Y(e.parentElement))}function Q(e,t){return!!e&&(e===t||Q(e.parentElement,t))}function X(e){let{summary:t,children:n,...r}=e;const c=(0,l.Z)(),s=(0,o.useRef)(null),{collapsed:u,setCollapsed:m}=(0,U.u)({initialState:!r.open}),[d,p]=(0,o.useState)(r.open),f=o.isValidElement(t)?t:o.createElement("summary",null,t??"Details");return o.createElement("details",(0,a.Z)({},r,{ref:s,open:d,"data-collapsed":u,className:(0,i.Z)(G.details,c&&G.isBrowser,r.className),onMouseDown:e=>{Y(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;Y(t)&&Q(t,s.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),f,o.createElement(U.z,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},o.createElement("div",{className:G.collapsibleContent},n)))}const J={details:"details_b_Ee"},K="alert alert--info";function ee(e){let{...t}=e;return o.createElement(X,(0,a.Z)({},t,{className:(0,i.Z)(K,J.details,t.className)}))}var te=n(2503);function ne(e){return o.createElement(te.Z,e)}const oe={containsTaskList:"containsTaskList_mC6p"};const re={img:"img_ev3q"};const ae="admonition_LlT9",ce="admonitionHeading_tbUL",le="admonitionIcon_kALy",ie="admonitionContent_S0QG";const se={note:{infimaClassName:"secondary",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:o.createElement(M.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:o.createElement(M.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 16 16"},o.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:o.createElement(M.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},ue={secondary:"note",important:"info",success:"tip",warning:"danger"};function me(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=o.Children.toArray(e),n=t.find((e=>o.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),r=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:r}}(e.children);return{...e,title:e.title??t,children:n}}const de={head:function(e){const t=o.Children.map(e.children,(e=>o.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...r}=e.props;return o.createElement(e.props.originalType,r)}return e}(e):e));return o.createElement(c.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return o.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,o.isValidElement)(e)&&t.includes(e.props?.mdxType)))?o.createElement("code",e):o.createElement(q,e)},a:function(e){return o.createElement(F.Z,e)},pre:function(e){return o.createElement(q,(0,o.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=o.Children.toArray(e.children),n=t.find((e=>o.isValidElement(e)&&"summary"===e.props?.mdxType)),r=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return o.createElement(ee,(0,a.Z)({},e,{summary:n}),r)},ul:function(e){return o.createElement("ul",(0,a.Z)({},e,{className:(t=e.className,(0,i.Z)(t,t?.includes("contains-task-list")&&oe.containsTaskList))}));var t},img:function(e){return o.createElement("img",(0,a.Z)({loading:"lazy"},e,{className:(t=e.className,(0,i.Z)(t,re.img))}));var t},h1:e=>o.createElement(ne,(0,a.Z)({as:"h1"},e)),h2:e=>o.createElement(ne,(0,a.Z)({as:"h2"},e)),h3:e=>o.createElement(ne,(0,a.Z)({as:"h3"},e)),h4:e=>o.createElement(ne,(0,a.Z)({as:"h4"},e)),h5:e=>o.createElement(ne,(0,a.Z)({as:"h5"},e)),h6:e=>o.createElement(ne,(0,a.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:r,icon:a}=me(e),c=function(e){const t=ue[e]??e,n=se[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),se.info)}(n),l=r??c.label,{iconComponent:s}=c,u=a??o.createElement(s,null);return o.createElement("div",{className:(0,i.Z)(d.k.common.admonition,d.k.common.admonitionType(e.type),"alert",`alert--${c.infimaClassName}`,ae)},o.createElement("div",{className:ce},o.createElement("span",{className:le},u),l),o.createElement("div",{className:ie},t))},mermaid:()=>null};function pe(e){let{children:t}=e;return o.createElement(r.Zo,{components:de},t)}},9407:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var o=n(7462),r=n(7294),a=n(6010),c=n(3743);const l={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},i="table-of-contents__link toc-highlight",s="table-of-contents__link--active";function u(e){let{className:t,...n}=e;return r.createElement("div",{className:(0,a.Z)(l.tableOfContents,"thin-scrollbar",t)},r.createElement(c.Z,(0,o.Z)({},n,{linkClassName:i,linkActiveClassName:s})))}},3743:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var o=n(7462),r=n(7294),a=n(6668);function c(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const o=n.slice(2,e.level);e.parentIndex=Math.max(...o),n[e.level]=t}));const o=[];return t.forEach((e=>{const{parentIndex:n,...r}=e;n>=0?t[n].children.push(r):o.push(r)})),o}function l(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:o}=e;return t.flatMap((e=>{const t=l({toc:e.children,minHeadingLevel:n,maxHeadingLevel:o});return function(e){return e.level>=n&&e.level<=o}(e)?[{...e,children:t}]:t}))}function i(e){const t=e.getBoundingClientRect();return t.top===t.bottom?i(e.parentNode):t}function s(e,t){let{anchorTopOffset:n}=t;const o=e.find((e=>i(e).top>=n));if(o){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(i(o))?o:e[e.indexOf(o)-1]??null}return e[e.length-1]??null}function u(){const e=(0,r.useRef)(0),{navbar:{hideOnScroll:t}}=(0,a.L)();return(0,r.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function m(e){const t=(0,r.useRef)(void 0),n=u();(0,r.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:o,linkActiveClassName:r,minHeadingLevel:a,maxHeadingLevel:c}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(o),l=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const o=[];for(let r=t;r<=n;r+=1)o.push(`h${r}.anchor`);return Array.from(document.querySelectorAll(o.join()))}({minHeadingLevel:a,maxHeadingLevel:c}),i=s(l,{anchorTopOffset:n.current}),u=e.find((e=>i&&i.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(r),e.classList.add(r),t.current=e):e.classList.remove(r)}(e,e===u)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,n])}function d(e){let{toc:t,className:n,linkClassName:o,isChild:a}=e;return t.length?r.createElement("ul",{className:a?void 0:n},t.map((e=>r.createElement("li",{key:e.id},r.createElement("a",{href:`#${e.id}`,className:o??void 0,dangerouslySetInnerHTML:{__html:e.value}}),r.createElement(d,{isChild:!0,toc:e.children,className:n,linkClassName:o}))))):null}const p=r.memo(d);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:i="table-of-contents__link",linkActiveClassName:s,minHeadingLevel:u,maxHeadingLevel:d,...f}=e;const h=(0,a.L)(),g=u??h.tableOfContents.minHeadingLevel,y=d??h.tableOfContents.maxHeadingLevel,v=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:o}=e;return(0,r.useMemo)((()=>l({toc:c(t),minHeadingLevel:n,maxHeadingLevel:o})),[t,n,o])}({toc:t,minHeadingLevel:g,maxHeadingLevel:y});return m((0,r.useMemo)((()=>{if(i&&s)return{linkClassName:i,linkActiveClassName:s,minHeadingLevel:g,maxHeadingLevel:y}}),[i,s,g,y])),r.createElement(p,(0,o.Z)({toc:v,className:n,linkClassName:i},f))}},7594:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,r,a]=t;if(o&&a){o=parseInt(o),a=parseInt(a);const e=o<a?1:-1;"-"!==r&&".."!==r&&"\u2025"!==r||(a+=e);for(let t=o;t!==a;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/assets/js/28d03809.10ee48b7.js b/assets/js/28d03809.10ee48b7.js new file mode 100644 index 000000000000..feb43c0f9761 --- /dev/null +++ b/assets/js/28d03809.10ee48b7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1423],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=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]||r;return n?o.createElement(m,i(i({ref:t},p),{},{components:n})):o.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[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,i[1]=s;for(var c=2;c<r;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3030:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const r={},i="Studio Overview",s={unversionedId:"creator/studio/readme",id:"creator/studio/readme",title:"Studio Overview",description:"Ethereal Engine Studio",source:"@site/docs/2_creator/2_studio/readme.md",sourceDirName:"2_creator/2_studio",slug:"/creator/studio/",permalink:"/etherealengine-docs/docs/creator/studio/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/2_studio/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Studio & Locations",permalink:"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations"},next:{title:"Asset Import Pipeline",permalink:"/etherealengine-docs/docs/creator/importing_assets/"}},l={},c=[{value:"1 Toolbar",id:"1-toolbar",level:2},{value:"1. File Menu",id:"1-file-menu",level:3},{value:"2: Advanced",id:"2-advanced",level:3},{value:"3. Active Instances",id:"3-active-instances",level:3},{value:"4. Transform Gizmo: Scale, Rotate, Move",id:"4-transform-gizmo--scale-rotate-move",level:3}],p={toc:c},d="wrapper";function h(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"studio-overview"},"Studio Overview"),(0,a.kt)("p",null,"Ethereal Engine Studio\nUI Overview\n",(0,a.kt)("img",{parentName:"p",src:"https://github.com/EtherealEngine/etherealengine-docs/assets/5104160/a26ad154-64f4-4681-a011-70af9f4213e1",alt:"image6"})),(0,a.kt)("p",null,"1: Toolbar"),(0,a.kt)("p",null,"2: Scene and File Directory "),(0,a.kt)("p",null,"3: Preview"),(0,a.kt)("p",null,"4: Viewport"),(0,a.kt)("p",null,"5: Hierarchy, Material Library, Node Graph"),(0,a.kt)("p",null,"6: Properties "),(0,a.kt)("p",null,"7: Assembly Menu"),(0,a.kt)("p",null,"8: User Profile "),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"1-toolbar"},"1 Toolbar"),(0,a.kt)("h3",{id:"1-file-menu"},"1. File Menu"),(0,a.kt)("p",null,"Create new scenes, import files, and save or export existing scenes. "),(0,a.kt)("h3",{id:"2-advanced"},"2: Advanced"),(0,a.kt)("p",null,"Toggle advanced options on Model or Avatar components.\nAdd and remove components in the Properties tab "),(0,a.kt)("h3",{id:"3-active-instances"},"3. Active Instances"),(0,a.kt)("p",null,"Active Instances shown here"),(0,a.kt)("h3",{id:"4-transform-gizmo--scale-rotate-move"},"4. Transform Gizmo: Scale, Rotate, Move"),(0,a.kt)("p",null," ","[ Y ]"," Scale\n","[ R ]"," Rotate\n","[ T ]"," Move"),(0,a.kt)("ol",{start:5},(0,a.kt)("li",{parentName:"ol"},"World Space or Object Space Transform - toggle to world or object\nSets your transform control to be oriented to the object(selection) or world\nWorld space relates to the entire scene\u2019s orientation\nObject space (your selection) relates to transforms made to a specific object in relationship to the world space")),(0,a.kt)("p",null,"[ Z ]"," Toggle World space or Object(Selection) space"),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Toggle Transform Pivot - modes: Selection, Center, Bottom, or Origin\nTo use, shift select objects, enter transform mode (Y, R, T), choose pivot type:\nSelection:the center pivot of the final asset you selected in the sequence\nCenter: a pivot that sits at an equal distance between all selections\nBottom: pivot that sits equally between all selections and at the bottom of your final selection in the sequence\nOrigin: sets pivot mode to the world origin (0,0,0)\n*it is recommended to use the Toggle Transform in conjunction with the World/Object Space transforms")),(0,a.kt)("p",null,"[ X ]"," Toggle between Selection, Center, or Bottom\n","[ E ]"," incrementally rotate around the Y axis, adopts the selected snapping degree value "),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Grid Snapping (toggle)\nTransform objects by a unit of measurement ","[.1 meters, .125 meters, 1 meter, 4 meters, etc]","\nRotate objects by a specific degrees ","[5o,10o, 20o, 90o, etc]")),(0,a.kt)("p",null,"[ C ]"," Toggle Snap Mode\n","[ E ]"," incrementally rotate around the Y axis, adopts the selected snapping degree value "),(0,a.kt)("ol",{start:8},(0,a.kt)("li",{parentName:"ol"},"Grid Visibility (toggle)\nSet grid spacing by meters")),(0,a.kt)("ol",{start:9},(0,a.kt)("li",{parentName:"ol"},"Render Mode\nHow you view materials in the Engine\n(Unlit, Lit, Shadows, Wireframe, Normals)")),(0,a.kt)("ol",{start:10},(0,a.kt)("li",{parentName:"ol"},"Preview Scene\nSpawns you into the scene ")),(0,a.kt)("ol",{start:11},(0,a.kt)("li",{parentName:"ol"},"Status (toggle)")),(0,a.kt)("p",null,"Show stats about the scene and gives you a clue as to how optimized your scene is\nMemory: Geometries, Textures\nRender: FPS, Frame Time, Calls(drawcalls), Triangles, Points, Lines"),(0,a.kt)("ol",{start:12},(0,a.kt)("li",{parentName:"ol"},"Helpers (toggle)\nView hidden information about your scene, ie: colliders ")),(0,a.kt)("ol",{start:13},(0,a.kt)("li",{parentName:"ol"},"Node Helpers (toggle)\nHelper geometry that helps components have visibility in the scene when inactive ")),(0,a.kt)("ol",{start:14},(0,a.kt)("li",{parentName:"ol"},"Take A Screenshot\nTakes a screenshot of your scene at the current view")),(0,a.kt)("p",null,"#2 Scene and File Directory "),(0,a.kt)("p",null,"Project Files\nContains all files associated with your project.\n.json files and various other file types in this menu are your project files and will show up automatically when you create a new scene."),(0,a.kt)("p",null,"Assets folder\nContains all assets you can import into your scene. When you use the Toolbar: File Menu to import files, they are delivered directly to the assets folder. To populate your scene simply drag them from the assets directly to your hierarchy.\nTip: Import may create a transform offset\nWhen some assets are loaded they automatically show up in the scene in the hierarchy and sometimes at an offset. Simply delete them from the hierarchy and re-drag them from your assets folder into your scene hierarchy to have them be set at home (0,0,0)"),(0,a.kt)("p",null,"#3 The Preview Panel\nThe preview panel allows you to preview certain files, currently supporting image, video and audio files "),(0,a.kt)("p",null,"#4 Viewport\nThe view of all things active inside your scene.\nObjects have the typical navigation controls\nX = red\nY = green\nZ = blue"),(0,a.kt)("p",null,"#5 Hierarchy & Material Library\nHierarchy\nThe scene Hierarchy contains all element currently in your scene (assets, lighting, items from the tool menu, etc)\nMaterial Library\nLocation of an assets materials and where you can select and edit them "),(0,a.kt)("p",null,"#6 Properties\nWhere you can access and edit detailed information about objects in your scene.\nSelect an object in the Hierarchy to view its Properties. This panel supports editing and adding actions to objects, ie: keying transforms, turning on animation tracks, looping motion, and adding components to objects "),(0,a.kt)("p",null,"Model URL\nShows the location of an object in your scene hierarchy "),(0,a.kt)("p",null,"Using the Advanced Tab (toolbar)\nBy activating the advanced tab from the toolbar you are able to add specific components to assets in your scene adding data to the entity.\nExplode objects that are imported as a collapsed group"),(0,a.kt)("p",null,"Types of Components "),(0,a.kt)("p",null,"#7 Assembly Menu"),(0,a.kt)("p",null,"Files\nModel\nCreates objects in the hierarchy. Drag a model from the assets folder into the URL box or drag assets directly from project files into the hierarchy\nVolumetric\nImport volumetric files. Accepts DRCS, UVOL, or Manifest Files, links to cloud hosting\nVideo\n2D plane accepts .mp4 .mkv .avi\nAudio\nImport audio clips, .mp3, .flac, .ogg, .wav, .m4a"),(0,a.kt)("p",null,"Scene Composition\nGround Plane\nCreate collision ground plane\nGroup\nCollection of models or assets\nAsset Prefab\nCreate prefabs from groups or objects that are saved to the assets folder. Saving requires specific naming: 'assetName'.xre.gltf\nCollider\nCreates a collision ball, cuboid, capsule, or cylinder to be manually placement"),(0,a.kt)("p",null,"Interaction\nSpawn Point\nA point where people will appear when they enter your scene\nPortal\nA portal to teleport a player to a port in a different location"),(0,a.kt)("p",null,"Lights\nHemisphere Light\nA light which illuminates the scene from directly overhead\nPoint Light\nA light which emits in all directions from a single point\nDirectional Light\nCreates a light that emits evenly in a single direction\nAmbient Light\nA combination of direct and indirect light, provides general lighting to all assets\nSpot Light\nCreates a light that shines in a specific direction"),(0,a.kt)("p",null,"Scripting\nInserts code into the scene by creating a new Entity Component System based on the provided .ts file"),(0,a.kt)("p",null,"FX\nOcean\nCube body of water\nParticle Emitter\nCreates a particle emitter\nCloud\nSprite based cloud volume\nWater\nCreates a circular water surface with ripple effect\nSpline\nCreate and customize curves"),(0,a.kt)("p",null,"Misc\nE-commerce shop\nCreate a shop, choose product from dropdown, click select product, click away, click back, select product item(.glb), select variant, select product, click away, click back, object will populate scene"),(0,a.kt)("p",null,"#8 User Profile",(0,a.kt)("br",{parentName:"p"}),"\n","Your Ethereal Engine account settings and linked account information"),(0,a.kt)("p",null,"The settings wheel icon allows you to turn up your scene resolution.\nIf you notice the scene looks blurry, go to the Graphics tab inside Settings and turn the Resolution tab all the way up."),(0,a.kt)("p",null,"Create a Project\nImport Assets\nYou can use the File menu to import assets or you can drag and drop them into the assets folder, when clicking and dragging notice a slight change in the color of the Engine, this signifies the engine is ready to ingest your file.\nImporting assets immediately creates them in the scene at an arbitrary location when imported via the viewport. It is recommended to delete that import and drag an asset directly from project files into the hierarchy to easily zero out your transforms.\nEthereal Engine accept the following file types"),(0,a.kt)("p",null,"3D Models .glb, .gltf\nImages .png, .tiff, .jpeg\nVolumetric DRCS, UVOL, Manifest Files on the Cloud\nVideos .mp4m, .mkv, .avi\nAudio .mp3, .mpeg, .m4a\nSave Project\nIn the File menu, click the save or save as button to save your scene\nSome projects require time to save so don't exit this window until a few minutes have passed\nEdit Materials\nEthereal Engine supports a PBR workflow and Vertex Colors\nPBR Workflow:\nDiffuse or Base Color Map\nMetalness Map\nRoughness Map\nNormal Map\nAmbient Occlusion (AO) Map\n*each of these loaded will represent one draw call, only use maps you absolutely need. You can drop the diffuse map and use our built in RGB color selector to save scene space."),(0,a.kt)("p",null,"Your asset materials are visible in the order below under the Material Library tab\nMaterial Library "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Asset Name\nmaterial name\nmaterial name\nmaterial name")),(0,a.kt)("p",null,"Material Types:\nMeshBasicMaterial\nThis material is not affected by lights.\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=meshba#api/en/materials/MeshBasicMaterial"},"https://threejs.org/docs/?q=meshba#api/en/materials/MeshBasicMaterial")," \t\t\t "),(0,a.kt)("p",null,"MeshStandardMaterial\nA standard physically based material, using Metallic-Roughness workflow.\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial"},"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial")),(0,a.kt)("p",null,"MeshMatcapMaterial\nMeshMatcapMaterial is defined by a MatCap (or Lit Sphere) texture, which encodes the \t\t\tmaterial color and shading.\nMeshPhysicalMaterial\nAn extension of the MeshStandardMaterial, providing more advanced physically-based rendering\n(added properties include: Clearcoat, Physically-based transparency, Advanced reflectivity, and Sheen)\nMeshLambertMaterial\nA material for non-shiny surfaces, without specular highlights.\nMeshPhongMaterial\nA material for shiny surfaces with specular highlights.\nMeshToonMaterial\nA material implementing toon shading.\nShaderMaterial\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=shadermat#api/en/materials/ShaderMaterial"},"https://threejs.org/docs/?q=shadermat#api/en/materials/ShaderMaterial"),"\nShadowMaterial\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=shadow#api/en/materials/ShadowMaterial"},"https://threejs.org/docs/?q=shadow#api/en/materials/ShadowMaterial")),(0,a.kt)("p",null,"Saving Changes\nAnytime you make a change to a model, you need to save your change.\nThis includes edits to the Position, Rotation, Scale, Normals, UVs, Materials and Attributes.\nAfter making your edit, go to the hierarchy and re-select your asset, in the Properties tab, scroll to the bottom and click the Save Changes button. If you want to Save As, in the url just above the Save Changes button, you can manually edit the name at the end of the url and click Save Changes. You can find the new version of your .glbl in the assets folder. "),(0,a.kt)("p",null,"Tip: Convert .gltfs or .usdz to .glb format in the engine using this method\nCompression\nThe in-engine compression menu is available when you select the model you want to run compression on from the Hierarchy. Scrolling down inside of the Properties panel you can expand the Model Transform Properties Menu.\nThere are three menus, gltF-Transform, Delete Attributes, Bake To Vertices."),(0,a.kt)("p",null,"gltF-Compression:\nRuns compression on the models geometry and image textures. Default settings work well for most models.\nThe Image Format menu allows you to either choose JPG, KTX2, or PNG for the image\u2019s compression format.\nThe Max Texture Size denotes the pixel scale of your image. Default settings downsize the textures to 1024 pixels x 1024 pixels\nPress Optimize to run the compression"),(0,a.kt)("p",null,"Delete Attributes:\nModels occasionally are imported with an excess of attributes taking up unwanted space, to delete the extra, unnecessary data list the attributes here with a space in between each attribute listed"),(0,a.kt)("p",null,"Bake To Vertices:\nThis tool bakes your texture to vertex color. By doing this we can eliminate the need for loading heavy images on some models. Vertex Baking transfers your PBR maps to the vertex of your model. We currently support diffuse, lightMap and emissive.\n*this method is for models that have a simple texture with either a single color or few details"),(0,a.kt)("p",null,"Animations in Objects\nAvatars\nTo turn on the animations of an imported model you would like to use as an avatar, in the Loop Animation tab you can select the animation track you wish to activate, \u201cmixamo.com\u201d.\nLoop Animations: loop the motion tracks available on your avatar\nChecking \u2018Is Avatar\u2019 allows you to use the animations built into the engine on your Avatar. "),(0,a.kt)("p",null,"Animated Geometry\nLoop Animations: loop the motion tracks available on your model"),(0,a.kt)("p",null,"Skybox/Cubemap\nThe Skybox Button from the Tools Panel allows you to create a Skybox for your scene.\nYou can choose between Color, Skybox, Cubemap, and Equirectangular\nColor: basic color as the sky\nSkybox: cubemap that surrounds your scene giving the look of being in an environment\nEquirectangular: sphere that surrounds your scene giving the look of being in an environment, recommended sources for equirectangular images are hdrihaven.com or "),(0,a.kt)("p",null,"Tip: HdriHaven has great free HDRI Resources"),(0,a.kt)("p",null,"Importing individual models (.glb/.gltf & .usdz)\nImport your model via the File Menu or drag and drop into the Viewport (when viewport changes color it is ready to ingest the file)\nWith the model in your Hierarchy, select it and scroll down in its Properties tab.\nRe-name to your desired description with a .glb or .gltf extension. You can find your saved model in your Assets tab in the Project Files directory\nscene should be determined by what your scene is composed of. Successful optimization is achieved by leveraging the appropriate use of detail per model.\nConverting Models to .glb (recommended)\nConvert .gltf to a .glb (in browser)\nRecommended to convert .gltf into .glbs for easier importing\n",(0,a.kt)("a",{parentName:"p",href:"https://glb-packer.glitch.me/"},"https://glb-packer.glitch.me/"),"\n",(0,a.kt)("a",{parentName:"p",href:"https://cartmagician.com/tools/3d-to-AR-converter"},"https://cartmagician.com/tools/3d-to-AR-converter")," (paid)\nConvert .fbx to .glb (app)\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/facebookincubator/FBX2glTF"},"https://github.com/facebookincubator/FBX2glTF"),"\nConvert .usd to .gltf (in browser)\n",(0,a.kt)("a",{parentName:"p",href:"https://products.groupdocs.app/conversion/usd-to-gltf"},"https://products.groupdocs.app/conversion/usd-to-gltf")),(0,a.kt)("p",null,"Using SampleStandardMaterial to enhance projects\nCustom settings for Glass, Plastic, Glow & Metal are provided below"),(0,a.kt)("p",null,"For the MeshStandardMaterial\n(re-create values below to simulate materials on your geometry)\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial"},"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial")),(0,a.kt)("p",null," Glass\t\t Plastic\t Glow\t\t\t Metal"),(0,a.kt)("p",null,"Tip: Exporting assets for basic materials\nIt is not required to have a texture map on all assets in 3D and it is recommended to use Standard Materials as often as possible. We recommended using basic materials for all basic metal, glass, emissive, and plastic assets (follow the sample material set-up above). You must denote which assets will have Standard Materials before you import your .glb to the engine. It is recommended to simply drag a native material from your chosen DCC or game engine prior to export, correctly name the basic material before exporting the .glb. Names given before import are the names the engine will inherit."),(0,a.kt)("p",null,"Saving Your Project "),(0,a.kt)("p",null,"Save As or Save Scene can be found in the File Menu.\nAllow the Engine a few minutes to save your file.\nTip: Change the view to create a thumbnail\nYou will be asked to create a thumbnail on Save which takes a screenshot from the current viewport view. Move your viewport to look at the desired view for your thumbnail before you click Save."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/291a898d.adadca59.js b/assets/js/291a898d.adadca59.js new file mode 100644 index 000000000000..4a1f896ca6b0 --- /dev/null +++ b/assets/js/291a898d.adadca59.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2606],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(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 a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?l(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},l=Object.keys(e);for(n=0;n<l.length;n++)r=l[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n<l.length;n++)r=l[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var i=n.createContext({}),s=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,l=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),m=o,f=u["".concat(i,".").concat(m)]||u[m]||d[m]||l;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=r.length,a=new Array(l);a[0]=m;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[u]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<l;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},9871:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>d,frontMatter:()=>l,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const l={},a="Control Center App",c={unversionedId:"host/devops_deployment/tutorials/ethereal_control_center/readme",id:"host/devops_deployment/tutorials/ethereal_control_center/readme",title:"Control Center App",description:"In this section you will various tutorials for Ethereal Engine Control System app.",source:"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/readme.md",sourceDirName:"1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center",slug:"/host/devops_deployment/tutorials/ethereal_control_center/",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Tutorials",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/"},next:{title:"Getting Started",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started"}},i={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"control-center-app"},"Control Center App"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine Control System app."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/33e7527e.bca6e6d3.js b/assets/js/33e7527e.bca6e6d3.js new file mode 100644 index 000000000000..f1e7da5c4b75 --- /dev/null +++ b/assets/js/33e7527e.bca6e6d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2984],{7085:e=>{e.exports=JSON.parse('{"name":"docusaurus-theme-search-algolia","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/393be207.7aa10cb1.js b/assets/js/393be207.7aa10cb1.js new file mode 100644 index 000000000000..d6af3d113dea --- /dev/null +++ b/assets/js/393be207.7aa10cb1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7414],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 p(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),i=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):p(p({},t),e)),r},u=function(e){var t=i(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=i(r),m=o,d=s["".concat(l,".").concat(m)]||s[m]||f[m]||a;return r?n.createElement(d,p(p({ref:t},u),{},{components:r})):n.createElement(d,p({ref:t},u))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,p=new Array(a);p[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:o,p[1]=c;for(var i=2;i<a;i++)p[i]=r[i];return n.createElement.apply(null,p)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3123:(e,t,r)=>{r.r(t),r.d(t,{contentTitle:()=>p,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={title:"Markdown page example"},p="Markdown page example",c={type:"mdx",permalink:"/etherealengine-docs/markdown-page",source:"@site/src/pages/markdown-page.md",title:"Markdown page example",description:"You don't need React to write simple standalone pages.",frontMatter:{title:"Markdown page example"}},l=[],i={toc:l},u="wrapper";function s(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},i,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"markdown-page-example"},"Markdown page example"),(0,o.kt)("p",null,"You don't need React to write simple standalone pages."))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3c3cda30.cb790227.js b/assets/js/3c3cda30.cb790227.js new file mode 100644 index 000000000000..fed02072ca6f --- /dev/null +++ b/assets/js/3c3cda30.cb790227.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[9037],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function l(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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){l(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,l=function(e,t){if(null==e)return{};var n,a,l={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},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,l=e.mdxType,o=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),p=c(n),m=l,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,i=new Array(o);i[0]=m;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[p]="string"==typeof e?e:l,i[1]=r;for(var c=2;c<o;c++)i[c]=n[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7360:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var a=n(7462),l=(n(7294),n(3905)),o=n(4401);const i={},r="Ethereal Engine on MicroK8s (Windows)",s={unversionedId:"host/devops_deployment/microk8s_windows",id:"host/devops_deployment/microk8s_windows",title:"Ethereal Engine on MicroK8s (Windows)",description:"This guide is intended for local environment and currently tested on Windows 11.",source:"@site/docs/1_host/2_devops_deployment/0_microk8s_windows.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/microk8s_windows",permalink:"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/0_microk8s_windows.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on MicroK8s (Linux)",permalink:"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux"},next:{title:"Ethereal Engine on Docker Desktop",permalink:"/etherealengine-docs/docs/host/devops_deployment/docker_desktop"}},c={},u=[{value:"Install Windows Subsystem for Linux (WSL)",id:"install-windows-subsystem-for-linux-wsl",level:2},{value:"Set Ubuntu as default WSL distribution",id:"set-ubuntu-as-default-wsl-distribution",level:3},{value:"Install Docker Desktop",id:"install-docker-desktop",level:2},{value:"Enable systemd in WSL",id:"enable-systemd-in-wsl",level:2},{value:"Enable localhostForwarding in WSL",id:"enable-localhostforwarding-in-wsl",level:2},{value:"Install Node",id:"install-node",level:2},{value:"Install Python 3",id:"install-python-3",level:2},{value:"Install Make",id:"install-make",level:2},{value:"Install kubectl and Helm",id:"install-kubectl-and-helm",level:2},{value:"Download and install MicroK8s",id:"download-and-install-microk8s",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Enabling MicroK8s Addons",id:"enabling-microk8s-addons",level:2},{value:"Add MicroK8s to Kubectl",id:"add-microk8s-to-kubectl",level:2},{value:"(Optional) Add MicroK8s to Lens",id:"optional-add-microk8s-to-lens",level:2},{value:"Enable MicroK8s access for local docker",id:"enable-microk8s-access-for-local-docker",level:2},{value:"Verify and troubleshoot MicroK8s",id:"verify-and-troubleshoot-microk8s",level:2},{value:"Update system hostfile to point to MicroK8s",id:"update-system-hostfile-to-point-to-microk8s",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"(Optional) Install Elastic Search and Kibana using Helm for Server Logs",id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Run build_microk8s.sh",id:"run-build_microk8ssh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],p={toc:u},d="wrapper";function m(e){let{components:t,...i}=e;return(0,l.kt)(d,(0,a.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"ethereal-engine-on-microk8s-windows"},"Ethereal Engine on MicroK8s (Windows)"),(0,l.kt)("p",null,"This guide is intended for local environment and currently tested on Windows 11."),(0,l.kt)("h2",{id:"install-windows-subsystem-for-linux-wsl"},"Install Windows Subsystem for Linux (WSL)"),(0,l.kt)("p",null,"Install Ubuntu distribution of Linux from Microsoft Store by using guide ",(0,l.kt)("a",{parentName:"p",href:"https://learn.microsoft.com/en-us/windows/wsl/install"},"here"),"."),(0,l.kt)("p",null,"Alternatively, you can follow these instructions as well:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://pureinfotech.com/install-wsl-windows-11/"},"How to install WSL")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/install-manual"},"Manual installation steps for WSL"))),(0,l.kt)("p",null,"Once WSL is installed, make sure to:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#set-up-your-linux-username-and-password"},"Set up your Linux username and password")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#update-and-upgrade-packages"},"Update and upgrade packages"))),(0,l.kt)("h3",{id:"set-ubuntu-as-default-wsl-distribution"},"Set Ubuntu as default WSL distribution"),(0,l.kt)("p",null,"In powershell/cmd run following command to see the list of distributions:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"wsl -l\n")),(0,l.kt)("p",null,"In the list you should be able to see ",(0,l.kt)("inlineCode",{parentName:"p"},"Ubuntu")," listed. Afterwards, run following command to set Ubuntu as default distribution:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"wsl -s Ubuntu\n")),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"WSL Ubuntu Default Distribution",src:n(8488).Z,width:"769",height:"435"})),(0,l.kt)("h2",{id:"install-docker-desktop"},"Install Docker Desktop"),(0,l.kt)("p",null,"Install docker desktop with WSL 2 backend. You can find the instructions ",(0,l.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/windows-install/"},"here"),"."),(0,l.kt)("p",null,"Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting ",(0,l.kt)("inlineCode",{parentName:"p"},"Settings > Resources > WSL Integration"),". Make sure to hit 'Apply & Restart'."),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"Docker Desktop WSL Distro",src:n(5238).Z,width:"1918",height:"1033"})),(0,l.kt)("h2",{id:"enable-systemd-in-wsl"},"Enable systemd in WSL"),(0,l.kt)("p",null,"Inside your Ubuntu instance, add the following modification to ",(0,l.kt)("inlineCode",{parentName:"p"},"/etc/wsl.conf"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-conf"},"[boot]\nsystemd=true\n")),(0,l.kt)("p",null,"Then restart your instance by running ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl --shutdown")," in PowerShell and relaunching Ubuntu. Upon launch you should have systemd running. You can check this with the command ",(0,l.kt)("inlineCode",{parentName:"p"},"systemctl list-unit-files --type=service")," which should show your services status."),(0,l.kt)("p",null,"You can read more about this on ",(0,l.kt)("a",{parentName:"p",href:"https://ubuntu.com/blog/ubuntu-wsl-enable-systemd"},"Ubuntu blog")," & ",(0,l.kt)("a",{parentName:"p",href:"https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/"},"Microsoft blog"),"."),(0,l.kt)("h2",{id:"enable-localhostforwarding-in-wsl"},"Enable localhostForwarding in WSL"),(0,l.kt)("p",null,"Create or update ",(0,l.kt)("inlineCode",{parentName:"p"},".wslconfig")," file located at ",(0,l.kt)("inlineCode",{parentName:"p"},"C:\\Users\\{USER_NAME}\\.wslconfig")," (Or ",(0,l.kt)("inlineCode",{parentName:"p"},"%UserProfile%\\.wslconfig"),") with following content:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-conf"},"[wsl2]\nlocalhostForwarding=true\n")),(0,l.kt)("p",null,"This requires WSL shutdown and reboot. Shutting down your terminal is insufficient. Also machine boot is not required. Simply run:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"wsl --shutdown (in Powershell) or \nwsl.exe --shutdown (within Ubuntu)\n")),(0,l.kt)("p",null,"Reference: ",(0,l.kt)("a",{parentName:"p",href:"https://stackoverflow.com/a/65707003/2077741"},"Custom hostname for servers running in WSL 2")),(0,l.kt)("h2",{id:"install-node"},"Install Node"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if node (",(0,l.kt)("inlineCode",{parentName:"p"},"node --version"),") isn't already installed on your machine. You can do so by first installing ",(0,l.kt)("inlineCode",{parentName:"p"},"nvm")," by running following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash\nsource ~/.profile\n\nexport NVM_DIR="$HOME/.nvm"\n[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh" # This loads nvm\n[ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n')),(0,l.kt)("p",null,"You can verify nvm by using ",(0,l.kt)("inlineCode",{parentName:"p"},"nvm --version")," command. Afterwards, install node by using:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"nvm install --lts\n")),(0,l.kt)("p",null,"You can verify nvm by using ",(0,l.kt)("inlineCode",{parentName:"p"},"node --version")," command."),(0,l.kt)("h2",{id:"install-python-3"},"Install Python 3"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if python 3 (",(0,l.kt)("inlineCode",{parentName:"p"},"pip3 --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y python3-pip\n")),(0,l.kt)("p",null,"You can verify python3 by using ",(0,l.kt)("inlineCode",{parentName:"p"},"python3 --version")," command."),(0,l.kt)("h2",{id:"install-make"},"Install Make"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if make (",(0,l.kt)("inlineCode",{parentName:"p"},"make --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y build-essential\n")),(0,l.kt)("p",null,"You can verify make by using ",(0,l.kt)("inlineCode",{parentName:"p"},"make --version")," command."),(0,l.kt)("h2",{id:"install-kubectl-and-helm"},"Install kubectl and Helm"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if ",(0,l.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl")," & ",(0,l.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm")," aren't already installed on your machine, install them."),(0,l.kt)("p",null,'Docker & Docker Compose should be installed if you successfully completed "',(0,l.kt)("a",{parentName:"p",href:"#install-docker-desktop"},"Install Docker Desktop"),'" step. You can verify by running ',(0,l.kt)("inlineCode",{parentName:"p"},"docker --version")," & ",(0,l.kt)("inlineCode",{parentName:"p"},"docker-compose --version")," commands in WSL Ubuntu terminal."),(0,l.kt)("h2",{id:"download-and-install-microk8s"},"Download and install MicroK8s"),(0,l.kt)("p",null,"Make sure to install MicroK8s in your WSL Ubuntu terminal. Instructions can be found ",(0,l.kt)("a",{parentName:"p",href:"https://ubuntu.com/tutorials/install-a-local-kubernetes-with-microk8s#1-overview"},"here")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo snap install microk8s --classic --channel=1.26/stable\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.")),(0,l.kt)("p",null,"While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it."),(0,l.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,l.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/etherealengine/etherealengine.git etherealengine\n")),(0,l.kt)("p",null,"If ",(0,l.kt)("inlineCode",{parentName:"p"},".env.local")," file does not exist in the root of your repo folder then create it by duplicating ",(0,l.kt)("inlineCode",{parentName:"p"},".env.local.default"),"."),(0,l.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,l.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,l.kt)("p",null,"If you run ",(0,l.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,l.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,l.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,l.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,l.kt)("inlineCode",{parentName:"p"},"./scripts/build_microk8s.sh"),"."),(0,l.kt)("h2",{id:"enabling-microk8s-addons"},"Enabling MicroK8s Addons"),(0,l.kt)("p",null,"Execute following command in your WSL Ubuntu terminal to enable MicroK8s addons"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3\n")),(0,l.kt)("h2",{id:"add-microk8s-to-kubectl"},"Add MicroK8s to Kubectl"),(0,l.kt)("p",null,"First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command in WSL Ubuntu terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config delete-context microk8s\nkubectl config delete-cluster microk8s-cluster\nkubectl config delete-user microk8s-admin\n")),(0,l.kt)("p",null,"Now, we will add microk8s configuration to kubectl config. We can do this by using following commands in WSL Ubuntu terminal. ",(0,l.kt)("a",{parentName:"p",href:"https://discuss.kubernetes.io/t/use-kubectl-with-microk8s/5313/6"},"Reference")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt\nkubectl config set-credentials microk8s-admin --token=\"$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')\"\nkubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin\n")),(0,l.kt)("p",null,"Afterwards you can use this newly create context by executing:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config use-context microk8s\n")),(0,l.kt)("p",null,"Now if you run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command then microk8s should be current context."),(0,l.kt)("h2",{id:"optional-add-microk8s-to-lens"},"(Optional) Add MicroK8s to Lens"),(0,l.kt)("p",null," If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool ",(0,l.kt)("a",{parentName:"p",href:"https://k8slens.dev/"},"Lens"),". Else you can print the configuration using following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"microk8s config\n")),(0,l.kt)("p",null,"In Lens, goto ",(0,l.kt)("inlineCode",{parentName:"p"},"File")," > ",(0,l.kt)("inlineCode",{parentName:"p"},"Add Cluster")," and paste the output of above command to add cluster."),(0,l.kt)("h2",{id:"enable-microk8s-access-for-local-docker"},"Enable MicroK8s access for local docker"),(0,l.kt)("p",null,"For MicroK8s we will be using MicroK8s local ",(0,l.kt)("a",{parentName:"p",href:"https://microk8s.io/docs/registry-built-in"},"registry")),(0,l.kt)("p",null,"Option 1: In Windows, add the following lines to ",(0,l.kt)("inlineCode",{parentName:"p"},"%userprofile%\\.docker\\daemon.json"),". Create this file if it does not already exists."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-json"},'{ \n "insecure-registries" : ["http://microk8s.registry:32000", "microk8s.registry:32000"] \n}\n')),(0,l.kt)("p",null,"Afterwards, restart docker from Powershell: ",(0,l.kt)("inlineCode",{parentName:"p"},"restart-service *docker*")),(0,l.kt)("p",null,"Option 2: Edit configuration as shown in below image. Make sure to hit 'Apply & Restart' after making changes."),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"Docker Desktop Configuration",src:n(7233).Z,width:"1920",height:"1030"})),(0,l.kt)("p",null,"Reference:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://stackoverflow.com/a/55352883/2077741"},"daemon.json file in W1indows")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/docker/docs/blob/62adddbb6b1f8d861c72f6ade2c50977fd57f481/registry/insecure.md#troubleshoot-insecure-registry"},"When using buildkit, http needs to be added")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://forums.docker.com/t/restart-docker-service-from-command-line/27331/2"},"Restart Docker service from command line"))),(0,l.kt)("h2",{id:"verify-and-troubleshoot-microk8s"},"Verify and troubleshoot MicroK8s"),(0,l.kt)("p",null,"Run following command and check if there is any warning. Its recommended to fix the warnings for MicroK8s to work properly."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo microk8s inspect\n")),(0,l.kt)("h2",{id:"update-system-hostfile-to-point-to-microk8s"},"Update system hostfile to point to MicroK8s"),(0,l.kt)("p",null,"You'll need to edit your hostfile to point certain domains to host machine IP address. First you need to find the IP address of your WSL. Run ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl hostname -I")," in powershell/cmd. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"C:\\Users\\hanzl>wsl hostname -I\n172.31.89.133 10.1.215.0\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Note: If you face issue while running above command, make sure that 'Ubuntu' distribution is selected as default. You can do so by running ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl /l")," to view distributions and then run ",(0,l.kt)("inlineCode",{parentName:"p"},"wslconfig /s Ubuntu")," to select distribution.")),(0,l.kt)("p",null,"From the above output, use ",(0,l.kt)("inlineCode",{parentName:"p"},"172.31.89.133")," as ",(0,l.kt)("inlineCode",{parentName:"p"},"{WSL_IP}"),"."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Note: Your ip would be different, this is just for example.")),(0,l.kt)("p",null,"Next, edit your Windows hostfile, this is done by editing ",(0,l.kt)("inlineCode",{parentName:"p"},"C:\\Windows\\System32\\drivers\\etc\\hosts"),". Add/Update the following lines:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-conf"},"{WSL_IP} local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org\n\n{WSL_IP} microk8s.registry\n")),(0,l.kt)("p",null,"Make sure to replace ",(0,l.kt)("inlineCode",{parentName:"p"},"{WSL_IP}")," with ip address from ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl hostname -I")," command."),(0,l.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod."),(0,l.kt)("p",null,"Make sure to save this file after you've edited it. Also, you will need to update hostfile with updated ip address after every Windows/WSL reboot."),(0,l.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,l.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,l.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,l.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,l.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,l.kt)("p",null,"Make sure that kubectl is pointed at MicroK8s by running ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),", which should say 'microk8s'. You can also run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,l.kt)("p",null,"Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones and ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("p",null,"You can run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state."),(0,l.kt)("h2",{id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs"},"(Optional) Install Elastic Search and Kibana using Helm for Server Logs"),(0,l.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,l.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,l.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,l.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,l.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,l.kt)("p",null,"Now check if the cluster members are up: ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,l.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,l.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,l.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana")),(0,l.kt)("p",null,"Check if all the pods are ready: ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,l.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,l.kt)("inlineCode",{parentName:"p"},"http://localhost:5601")," in your browser"),(0,l.kt)("p",null,"In order to connect logger with elasticsearch, update ",(0,l.kt)("inlineCode",{parentName:"p"},"local.microk8s.template.values.yaml")," env ",(0,l.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"local.microk8s.template.values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("h2",{id:"run-build_microk8ssh"},"Run build_microk8s.sh"),(0,l.kt)("p",null,"When microk8s is running, run the following command from the root of the Ethereal Engine repo in WSL Ubuntu terminal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"export REGISTRY_HOST=microk8s.registry; export MYSQL_HOST=kubernetes.docker.internal;bash ./scripts/build_microk8s.sh\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,l.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your WSL terminal:")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,l.kt)("p",null,"The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on ",(0,l.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)"),(0,l.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached."),(0,l.kt)("p",null,"Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting ",(0,l.kt)("a",{parentName:"p",href:"http://microk8s.registry:32000/v2/_catalog"},"http://microk8s.registry:32000/v2/_catalog"),"."),(0,l.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,l.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"template")," for this file in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,l.kt)("p",null,"If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable ",(0,l.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to ",(0,l.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,l.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,l.kt)("p",null,'Before this step, ensure that all the agones and redis pods are in "Running" state. You can check pods status using the below command.'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl get pods\n")),(0,l.kt)("p",null,"Run the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("p",null,"After a minute or so, running ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting ",(0,l.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run ",(0,l.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),". The API pods will restart and will now not attempt to reinit the database on boot."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,l.kt)(o.ZP,{mdxType:"AcceptCertificates"}))}m.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>r});var a=n(7462),l=(n(7294),n(3905));const o={toc:[]},i="wrapper";function r(e){let{components:t,...n}=e;return(0,l.kt)(i,(0,a.Z)({},o,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,l.kt)("p",null,"Go to ",(0,l.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,l.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,l.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,l.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,l.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}r.isMDXComponent=!0},7233:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg"},5238:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg"},8488:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg"}}]); \ No newline at end of file diff --git a/assets/js/3ec03ade.21fb0b42.js b/assets/js/3ec03ade.21fb0b42.js new file mode 100644 index 000000000000..06627196a1b2 --- /dev/null +++ b/assets/js/3ec03ade.21fb0b42.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6916],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),h=o,f=p["".concat(l,".").concat(h)]||p[h]||d[h]||a;return n?r.createElement(f,i(i({ref:t},u),{},{components:n})):r.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var c=2;c<a;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},5545:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={},i="Running on Static IP under WSL2",s={unversionedId:"host/installation/running_on_static_IP",id:"host/installation/running_on_static_IP",title:"Running on Static IP under WSL2",description:"Follow these steps to run the engine on a static IP instead of localhost. In",source:"@site/docs/1_host/1_installation/5_running_on_static_IP.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/running_on_static_IP",permalink:"/etherealengine-docs/docs/host/installation/running_on_static_IP",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/5_running_on_static_IP.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Advanced Setup",permalink:"/etherealengine-docs/docs/host/installation/advanced_setup"},next:{title:"Troubleshooting",permalink:"/etherealengine-docs/docs/host/installation/install_troubleshooting"}},l={},c=[],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"running-on-static-ip-under-wsl2"},"Running on Static IP under WSL2"),(0,o.kt)("p",null,"Follow these steps to run the engine on a static IP instead of localhost. In\nmost cases you should be able to simply access the engine using the public IP\nassigned to your device, but if you run into any issues or if you are running\nthe stack on WSL2 then you can refer to the following directions."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Replace all localhost values with the static IP you want to run the stack on\nin your ",(0,o.kt)("inlineCode",{parentName:"li"},".env.local")," file."),(0,o.kt)("li",{parentName:"ol"},"Open a PowerShell terminal as admin. And run the ",(0,o.kt)("inlineCode",{parentName:"li"},"wsl2-port-forwarding.ps1"),"\nscript present under ",(0,o.kt)("inlineCode",{parentName:"li"},"/scripts")," directory.\nNote: Make sure all of the required ports are present in ports array of the\n",(0,o.kt)("inlineCode",{parentName:"li"},"wsl2-port-forwarding.ps1")," script."),(0,o.kt)("li",{parentName:"ol"},"And now just run the engine as you normally would and everything should be\naccessible over the static IP."),(0,o.kt)("li",{parentName:"ol"},"If you get any errors related to ",(0,o.kt)("strong",{parentName:"li"},"localhost:8642"),", then make sure that none of\nthe assets in your scene have been saved localhost path. If there are then\nreplace localhost with the static IP in the respective asset's path too.")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/46dcad74.49e01d47.js b/assets/js/46dcad74.49e01d47.js new file mode 100644 index 000000000000..3e4527ccf7f3 --- /dev/null +++ b/assets/js/46dcad74.49e01d47.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5520],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>k});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 o(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 i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),c=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=c(e.components);return r.createElement(s.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=a,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return t?r.createElement(k,i(i({ref:n},p),{},{components:t})):r.createElement(k,i({ref:n},p))}));function k(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=t[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},6506:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=t(7462),a=(t(7294),t(3905));const o={},i="Troubleshooting",l={unversionedId:"host/installation/install_troubleshooting",id:"host/installation/install_troubleshooting",title:"Troubleshooting",description:"Browser Debug",source:"@site/docs/1_host/1_installation/6_install_troubleshooting.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/install_troubleshooting",permalink:"/etherealengine-docs/docs/host/installation/install_troubleshooting",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/6_install_troubleshooting.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Running on Static IP under WSL2",permalink:"/etherealengine-docs/docs/host/installation/running_on_static_IP"},next:{title:"Old Docker Instructions",permalink:"/etherealengine-docs/docs/host/installation/docker"}},s={},c=[{value:"Browser Debug",id:"browser-debug",level:3},{value:"Invalid Certificate errors in local environment",id:"invalid-certificate-errors-in-local-environment",level:3},{value:"Allow instanceserver address connection via installing local Certificate Authority",id:"allow-instanceserver-address-connection-via-installing-local-certificate-authority",level:3},{value:"Allow local file http-server connection with invalid certificate",id:"allow-local-file-http-server-connection-with-invalid-certificate",level:3},{value:"Allow instanceserver address connection with invalid certificate",id:"allow-instanceserver-address-connection-with-invalid-certificate",level:3},{value:"AccessDenied connecting to mariadb",id:"accessdenied-connecting-to-mariadb",level:3},{value:"Error: listen EADDRINUSE :::3030",id:"error-listen-eaddrinuse-3030",level:3},{value:"'CORS error' in terminal",id:"cors-error-in-terminal",level:3},{value:"Default blank screen",id:"default-blank-screen",level:3},{value:"Instanceserver or resource loading error?",id:"instanceserver-or-resource-loading-error",level:3},{value:"To install a new package for editor react components in monorepo",id:"to-install-a-new-package-for-editor-react-components-in-monorepo",level:3},{value:"Using Local Storage instead of MinIO",id:"using-local-storage-instead-of-minio",level:3},{value:"Accessing MinIO S3 storage provider running in local docker",id:"accessing-minio-s3-storage-provider-running-in-local-docker",level:3},{value:"Clear all data from MinIO S3 storage provider running in local docker",id:"clear-all-data-from-minio-s3-storage-provider-running-in-local-docker",level:3},{value:"DB not seeding routes (E.g. Error: No project installed- please contact site admin)",id:"db-not-seeding-routes-eg-error-no-project-installed--please-contact-site-admin",level:3},{value:"Weird issues with your database?",id:"weird-issues-with-your-database",level:3}],p={toc:c},d="wrapper";function u(e){let{components:n,...t}=e;return(0,a.kt)(d,(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"troubleshooting"},"Troubleshooting"),(0,a.kt)("h3",{id:"browser-debug"},"Browser Debug"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"p key")," debug colliders view"),(0,a.kt)("h3",{id:"invalid-certificate-errors-in-local-environment"},"Invalid Certificate errors in local environment"),(0,a.kt)("p",null,"As of this writing, the cert provided in the ethereal engine package for local use\nis not adequately signed. Browsers will throw up warnings about going to insecure pages.\nYou should be able to tell the browser to ignore it, usually by clicking on some sort\nof 'advanced options' button or link and then something along the lines of 'go there anyway'."),(0,a.kt)("p",null,"Chrome sometimes does not show a clickable option on the warning. If so, just\ntype ",(0,a.kt)("inlineCode",{parentName:"p"},"badidea")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"thisisunsafe")," when on that page. You don't enter that into the\naddress bar or into a text box, Chrome is just passively listening for those commands."),(0,a.kt)("h3",{id:"allow-instanceserver-address-connection-via-installing-local-certificate-authority"},"Allow instanceserver address connection via installing local Certificate Authority"),(0,a.kt)("p",null,"For more detailed instructions check: ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/FiloSottile/mkcert"},"https://github.com/FiloSottile/mkcert")),(0,a.kt)("p",null,"Short version (common for development process on Ubuntu):"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"sudo apt install libnss3-tools")),(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"brew install mkcert")," (if you don't have brew, check it's page: ",(0,a.kt)("a",{parentName:"li",href:"https://brew.sh/"},"https://brew.sh/"),")"),(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"mkcert --install")),(0,a.kt)("li",{parentName:"ol"},"Navigate to ",(0,a.kt)("inlineCode",{parentName:"li"},"./certs")," folder"),(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1"))),(0,a.kt)("h3",{id:"allow-local-file-http-server-connection-with-invalid-certificate"},"Allow local file http-server connection with invalid certificate"),(0,a.kt)("p",null,"Open the developer tools in your browser by pressing ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Shift+i")," at the\nsame time. Go to the 'Console' tab and look at the message history. If there are\nred errors that say something like\n",(0,a.kt)("inlineCode",{parentName:"p"},"GET https://127.0.0.1:3030/socket.io/?EIO=3&transport=polling&t=NXlZLTa net::ERR_CERT_AUTHORITY_INVALID"),",\nthen right-click that URL, then select 'Open in new tab', and accept the invalid certificate."),(0,a.kt)("h3",{id:"allow-instanceserver-address-connection-with-invalid-certificate"},"Allow instanceserver address connection with invalid certificate"),(0,a.kt)("p",null,"The instanceserver functionality is hosted on an address other than 127.0.0.1 in the local\nenvironment. Accepting an invalid certificate for 127.0.0.1 will not apply to this address.\nOpen the dev console for Chrome/Firefox by pressing ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Shift+i")," simultaneously, and\ngo to the Console or Network tabs."),(0,a.kt)("p",null,"If you see errors about not being able to connect to\nsomething like ",(0,a.kt)("inlineCode",{parentName:"p"},"https://192.168.0.81:3031/socket.io/?location=<foobar>"),", right click on\nthat URL and open it in a new tab. You should again get a warning page about an invalid\ncertificate, and you again need to allow it. "),(0,a.kt)("h3",{id:"accessdenied-connecting-to-mariadb"},"AccessDenied connecting to mariadb"),(0,a.kt)("p",null,"Make sure you don't have another instance of mariadb running on port 3306"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"lsof -i :3306\n")),(0,a.kt)("p",null,"On Linux, you can also check if any processes are running on port 3306 with\n",(0,a.kt)("inlineCode",{parentName:"p"},"sudo netstat -utlp | grep 3306"),"\nThe last column should look like ",(0,a.kt)("inlineCode",{parentName:"p"},"<ID>/<something"),"\nYou can kill any running process with ",(0,a.kt)("inlineCode",{parentName:"p"},"sudo kill <ID>")),(0,a.kt)("h3",{id:"error-listen-eaddrinuse-3030"},"Error: listen EADDRINUSE :::3030"),(0,a.kt)("p",null,"Check which process is using port 3030 and kill"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"killall -9 node \n")),(0,a.kt)("p",null,"Or"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"lsof -i :3030\nkill -3 <proccessIDfromPreviousCommand>\n")),(0,a.kt)("h3",{id:"cors-error-in-terminal"},"'CORS error' in terminal"),(0,a.kt)("p",null,"Try accessing the page using ",(0,a.kt)("inlineCode",{parentName:"p"},"https://localhost:3000"),"\ninstead of ",(0,a.kt)("inlineCode",{parentName:"p"},"https://127.0.0.1:3000")),(0,a.kt)("h3",{id:"default-blank-screen"},"Default blank screen"),(0,a.kt)("p",null,"Try typing ",(0,a.kt)("inlineCode",{parentName:"p"},"\u201cthisisunsafe\u201d")," or ",(0,a.kt)("inlineCode",{parentName:"p"},'"iknowwhatiamdoing"')," then reload page"),(0,a.kt)("h3",{id:"instanceserver-or-resource-loading-error"},"Instanceserver or resource loading error?"),(0,a.kt)("p",null,"Open dev console, click on the GET link in new tab and accept certificate by\ntyping ",(0,a.kt)("inlineCode",{parentName:"p"},"thisisunsafe\u201d")," or ",(0,a.kt)("inlineCode",{parentName:"p"},'"iknowwhatiamdoing"')," then reload original page"),(0,a.kt)("h3",{id:"to-install-a-new-package-for-editor-react-components-in-monorepo"},"To install a new package for editor react components in monorepo"),(0,a.kt)("p",null,"Type in terminal"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," npm i <packagename> -w @etherealengine/editor\n")),(0,a.kt)("h3",{id:"using-local-storage-instead-of-minio"},"Using Local Storage instead of MinIO"),(0,a.kt)("p",null,"Currently MinIO is used as default storage for local development. If you want to use local storage then do following steps:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"set ",(0,a.kt)("inlineCode",{parentName:"li"},"VITE_FILE_SERVER")," to the commented values under ",(0,a.kt)("inlineCode",{parentName:"li"},"# Use following value for local file server")," and comment out the values above it."),(0,a.kt)("li",{parentName:"ul"},"set ",(0,a.kt)("inlineCode",{parentName:"li"},"STORAGE_PROVIDER")," to ",(0,a.kt)("inlineCode",{parentName:"li"},"local"))),(0,a.kt)("h3",{id:"accessing-minio-s3-storage-provider-running-in-local-docker"},"Accessing MinIO S3 storage provider running in local docker"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Using ",(0,a.kt)("a",{parentName:"strong",href:"https://min.io/docs/minio/linux/administration/minio-console.html"},"MinIO Console"),":")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"When MinIO contain is running in your docker, navigate to ",(0,a.kt)("a",{parentName:"p",href:"https://localhost:9001/"},"https://localhost:9001/")," in your browser."),(0,a.kt)("blockquote",{parentName:"li"},(0,a.kt)("p",{parentName:"blockquote"},"Make sure to accept invalid certificate warning."))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Login using username as ",(0,a.kt)("inlineCode",{parentName:"p"},"server")," and password as ",(0,a.kt)("inlineCode",{parentName:"p"},"password"),"."),(0,a.kt)("blockquote",{parentName:"li"},(0,a.kt)("p",{parentName:"blockquote"},"You can find these credentials in ",(0,a.kt)("inlineCode",{parentName:"p"},"scripts/docker-compose.yml")," as ",(0,a.kt)("inlineCode",{parentName:"p"},"MINIO_ROOT_USER")," & ",(0,a.kt)("inlineCode",{parentName:"p"},"MINIO_ROOT_PASSWORD"))))),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Using ",(0,a.kt)("a",{parentName:"strong",href:"https://s3browser.com/"},"S3 Browser")," (Windows Only):")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Download & install S3 Browser from ",(0,a.kt)("a",{parentName:"li",href:"https://s3browser.com/download.aspx"},"https://s3browser.com/download.aspx"),"."),(0,a.kt)("li",{parentName:"ul"},"Launch and connect using following details:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Account Type: ",(0,a.kt)("strong",{parentName:"li"},"S3 Compatible Storage")),(0,a.kt)("li",{parentName:"ul"},"REST Endpoint: ",(0,a.kt)("strong",{parentName:"li"},"127.0.0.1:9000")),(0,a.kt)("li",{parentName:"ul"},"Access Key ID: ",(0,a.kt)("strong",{parentName:"li"},"server")),(0,a.kt)("li",{parentName:"ul"},"Secret Access Key: ",(0,a.kt)("strong",{parentName:"li"},"password")),(0,a.kt)("li",{parentName:"ul"},"Use secure transfer (SSL/TLS): ",(0,a.kt)("strong",{parentName:"li"},"Check / On / True"))))),(0,a.kt)("h3",{id:"clear-all-data-from-minio-s3-storage-provider-running-in-local-docker"},"Clear all data from MinIO S3 storage provider running in local docker"),(0,a.kt)("p",null,"Run following commands in your terminal:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," docker container stop etherealengine_minio_s3\n docker container rm etherealengine_minio_s3\n docker container prune --force\n docker volume prune --force\n npm run dev-docker\n npm run dev-reinit\n")),(0,a.kt)("h3",{id:"db-not-seeding-routes-eg-error-no-project-installed--please-contact-site-admin"},"DB not seeding routes (E.g. Error: No project installed- please contact site admin)"),(0,a.kt)("p",null,"Try"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," npm run dev-reinit \n")),(0,a.kt)("p",null,"or"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," docker container stop etherealengine_db\n docker container rm etherealengine_db\n docker container prune --force\n npm run dev-docker\n npm run dev-reinit\n")),(0,a.kt)("h3",{id:"weird-issues-with-your-database"},"Weird issues with your database?"),(0,a.kt)("p",null,"Try"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev-reinit\n")),(0,a.kt)("p",null,"Or if on windows"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev-reinit-windows\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/47408852.86d4c0f1.js b/assets/js/47408852.86d4c0f1.js new file mode 100644 index 000000000000..9faaa2873478 --- /dev/null +++ b/assets/js/47408852.86d4c0f1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2130],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function s(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function o(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?s(Object(n),!0).forEach((function(e){r(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function i(t,e){if(null==t)return{};var n,a,r=function(t,e){if(null==t)return{};var n,a,r={},s=Object.keys(t);for(a=0;a<s.length;a++)n=s[a],e.indexOf(n)>=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);for(a=0;a<s.length;a++)n=s[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var l=a.createContext({}),d=function(t){var e=a.useContext(l),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},p=function(t){var e=d(t.components);return a.createElement(l.Provider,{value:e},t.children)},u="mdxType",g={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},c=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,s=t.originalType,l=t.parentName,p=i(t,["components","mdxType","originalType","parentName"]),u=d(n),c=r,m=u["".concat(l,".").concat(c)]||u[c]||g[c]||s;return n?a.createElement(m,o(o({ref:e},p),{},{components:n})):a.createElement(m,o({ref:e},p))}));function m(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var s=n.length,o=new Array(s);o[0]=c;var i={};for(var l in e)hasOwnProperty.call(e,l)&&(i[l]=e[l]);i.originalType=t,i[u]="string"==typeof t?t:r,o[1]=i;for(var d=2;d<s;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},496:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>o,default:()=>g,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(7462),r=(n(7294),n(3905));const s={},o="Testing",i={unversionedId:"creator/testing/readme",id:"creator/testing/readme",title:"Testing",description:"Automated testing is a cornerstone to successful software development. Tests are",source:"@site/docs/2_creator/6_testing/readme.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/",permalink:"/etherealengine-docs/docs/creator/testing/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Unreal Bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge"},next:{title:"Testing Basics",permalink:"/etherealengine-docs/docs/creator/testing/testing_intro"}},l={},d=[{value:"SMTP Testing",id:"smtp-testing",level:2},{value:"Unit tests",id:"unit-tests",level:2},{value:"Integration tests",id:"integration-tests",level:2},{value:"Unit vs Integration Tests (source)",id:"unit-vs-integration-tests-source",level:2},{value:"System tests",id:"system-tests",level:2},{value:"End-to-end tests",id:"end-to-end-tests",level:2},{value:"System vs End-to-end Tests (source)",id:"system-vs-end-to-end-tests-source",level:2},{value:"White-box vs Black-box testing",id:"white-box-vs-black-box-testing",level:2},{value:"The Testing Pyramid",id:"the-testing-pyramid",level:2}],p={toc:d},u="wrapper";function g(t){let{components:e,...n}=t;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"testing"},"Testing"),(0,r.kt)("p",null,"Automated testing is a cornerstone to successful software development. Tests are\nnot just to ensure that your application is working as intended, they are also\nto ensure that ",(0,r.kt)("strong",{parentName:"p"},"existing features aren't broken by any newly introduced features\nor code"),", aka ",(0,r.kt)("strong",{parentName:"p"},"regression bugs"),". The latter tends to hold more value, as it\nmakes the software sturdy and less prone to these types of bugs during active\ndevelopment of a project. Regression bugs will quickly stall the development of\na project at a certain level of complexity, effectively preventing progress."),(0,r.kt)("h2",{id:"smtp-testing"},"SMTP Testing"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://mailtrap.io/inboxes"},"https://mailtrap.io/inboxes")),(0,r.kt)("p",null,"Add credentials in ",(0,r.kt)("inlineCode",{parentName:"p"},".env.local")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-dotenv"},"SMTP_HOST=smtp.mailtrap.io\nSMTP_PORT=2525\nSMTP_USER=<mailtrap-user>\nSMTP_PASS=<mailtrap-password>\n")),(0,r.kt)("h2",{id:"unit-tests"},"Unit tests"),(0,r.kt)("p",null,"Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const add2 = x => x + 2\n\nit('should add 2 to a given number', () => {\n strictEqual(add2(1), 3)\n})\n")),(0,r.kt)("h2",{id:"integration-tests"},"Integration tests"),(0,r.kt)("p",null,"Integration tests focus on testing bundles of code units. A composition of functions, for example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const addTwo = x => x + 2\nconst multThree = x => x * 3\nconst halve = x => x / 2\n\nconst algorithm = x => {\n x = addTwo(x)\n x = multThree(x)\n x = halve(x)\n return x\n}\n\nit('should apply the entire algorithm correctly', () => {\n strictEqual(algorithm(4), 9)\n})\n")),(0,r.kt)("h2",{id:"unit-vs-integration-tests-source"},"Unit vs Integration Tests (",(0,r.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-unit-testing-and-integration-testing/"},"source"),")"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Unit Testing"),(0,r.kt)("th",{parentName:"tr",align:null},"Integration Testing"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"In unit testing each module of the software is tested separately."),(0,r.kt)("td",{parentName:"tr",align:null},"In integration testing all modules of the the software are tested combined.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"In unit testing the tester knows the internal design of the software."),(0,r.kt)("td",{parentName:"tr",align:null},"In integration testing the tester doesn't know the internal design of the software.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is performed first of all testing processes."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is performed after unit testing, and before system/end-to-end tests.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is a white box testing."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is a black box testing.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is performed by the developer."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is performed by the tester.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Detection of defects in unit testing is easy."),(0,r.kt)("td",{parentName:"tr",align:null},"Detection of defects in integration testing is difficult.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It tests parts of the project without waiting for others to be completed."),(0,r.kt)("td",{parentName:"tr",align:null},"It tests only after the completion of all parts.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is less costly."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is more costly.")))),(0,r.kt)("h2",{id:"system-tests"},"System tests"),(0,r.kt)("p",null,"System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test)."),(0,r.kt)("h2",{id:"end-to-end-tests"},"End-to-end tests"),(0,r.kt)("p",null,"End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow)."),(0,r.kt)("h2",{id:"system-vs-end-to-end-tests-source"},"System vs End-to-end Tests (",(0,r.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-system-testing-and-end-to-end-testing/"},"source"),")"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"System Testing"),(0,r.kt)("th",{parentName:"tr",align:null},"End-to-end Testing"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"In system testing, whole software or application is tested at a time."),(0,r.kt)("td",{parentName:"tr",align:null},"In end-to-end testing, behavioral flow of the software is tested.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"System testing only tests the specific software system."),(0,r.kt)("td",{parentName:"tr",align:null},"It tests the software system and the connected systems both.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"The functionality of the software is tested."),(0,r.kt)("td",{parentName:"tr",align:null},"Flow from end-to-end is tested.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It validates the software system as per standards and specifications."),(0,r.kt)("td",{parentName:"tr",align:null},"It validated all the interfaces of the software.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Knowledge of interconnected systems is not required."),(0,r.kt)("td",{parentName:"tr",align:null},"Knowledge about interconnected systems is required.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It is carried out once integration testing is performed."),(0,r.kt)("td",{parentName:"tr",align:null},"It is performed after the system testing.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It is performed both manually and automated."),(0,r.kt)("td",{parentName:"tr",align:null},"It is generally performed manually.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It is the super set of end-to-end testing."),(0,r.kt)("td",{parentName:"tr",align:null},"It is considered as subset of the system testing.")))),(0,r.kt)("h2",{id:"white-box-vs-black-box-testing"},"White-box vs Black-box testing"),(0,r.kt)("p",null,"Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing."),(0,r.kt)("p",null,"Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing."),(0,r.kt)("h2",{id:"the-testing-pyramid"},"The Testing Pyramid"),(0,r.kt)("p",null,"A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution."),(0,r.kt)("p",null,"70% Unit tests"),(0,r.kt)("p",null,"20% Integration tests"),(0,r.kt)("p",null,"10% End-to-end tests"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"}," /```\\\n / E2E \\\n /_______\\\n / \\\n /Integration\\\n /_____________\\\n / \\\n / Unit \\\n/___________________\\\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4972.512e2090.js b/assets/js/4972.512e2090.js new file mode 100644 index 000000000000..2aba19d26b5b --- /dev/null +++ b/assets/js/4972.512e2090.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4972],{4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>i});var a=n(7294),l=n(5999),o=n(833),r=n(7452);function i(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/assets/js/4a109b8c.cb0176b6.js b/assets/js/4a109b8c.cb0176b6.js new file mode 100644 index 000000000000..6ca27b288201 --- /dev/null +++ b/assets/js/4a109b8c.cb0176b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[943],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.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,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var p=2;p<o;p++)i[p]=n[p];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8960:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const o={},i="Projects",l={unversionedId:"creator/development/projects_overview",id:"creator/development/projects_overview",title:"Projects",description:"Projects are folders that contain all your custom code, assets and scenes. They",source:"@site/docs/2_creator/4_development/0_projects_overview.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/projects_overview",permalink:"/etherealengine-docs/docs/creator/development/projects_overview",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/0_projects_overview.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Development",permalink:"/etherealengine-docs/docs/creator/development/"},next:{title:"State Management",permalink:"/etherealengine-docs/docs/creator/development/state_management"}},s={},p=[{value:"File Structure",id:"file-structure",level:2},{value:"Config",id:"config",level:2},{value:"Hooks",id:"hooks",level:3},{value:"Thumbnail",id:"thumbnail",level:3},{value:"Routes",id:"routes",level:3},{value:"Webapp Injection",id:"webapp-injection",level:3},{value:"World Injection",id:"world-injection",level:3},{value:"Services",id:"services",level:3},{value:"Database Seeding",id:"database-seeding",level:3},{value:"i18n",id:"i18n",level:3}],c={toc:p},d="wrapper";function u(e){let{components:t,...o}=e;return(0,r.kt)(d,(0,a.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"projects"},"Projects"),(0,r.kt)("p",null,"Projects are folders that contain all your custom code, assets and scenes. They\nare version controlled using git & github, and can be installed to any deployment\nwith a single click. (more on that in the ",(0,r.kt)("a",{parentName:"p",href:"./3_editor_scenes_locations.md"},"next chapter"),")"),(0,r.kt)("p",null,"Pictured below is an example of 4 projects installed. By default, only the\n",(0,r.kt)("inlineCode",{parentName:"p"},"default-project")," is installed, which in a production environment is read only.\nYou can find the default project under ",(0,r.kt)("inlineCode",{parentName:"p"},"/packages/projects/default-project/")),(0,r.kt)("p",null,"In a production environment, the builder process will install all projects\naccording to the ",(0,r.kt)("inlineCode",{parentName:"p"},"project")," database table and will download files from the\nstorage provider. In a local development environment, the local file system is\nalways the source of truth. Any project folders added or removed from the file\nsystem will be automatically added or removed from the database. This is to\nensure there is no accidental loss of data, as these project folders are all git\nrepositories."),(0,r.kt)("p",null,(0,r.kt)("img",{src:n(8098).Z,width:"263",height:"241"})),(0,r.kt)("h2",{id:"file-structure"},"File Structure"),(0,r.kt)("p",null,"Projects have a few conventions."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"assets/")," is where files uploaded from the editor will be uploaded to")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"src/")," is where code assets can be served from")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"tests/")," is where test files can be run")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"sceneName.scene.json")," is a scene file")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"sceneName.thumbnail.png")," is an auto-generated scene thumbnail file")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"xrengine.config.ts")," the project configuration, where client routes, database\nmodels, feathers services and the project thumbnail can be defined"))),(0,r.kt)("p",null,"A project must also have a package.json to provide custom dependencies, and to define\nthe project name, project version, and Ethereal Engine version it is known to work with."),(0,r.kt)("p",null,"Systems imported from a scene MUST have their filename end with ",(0,r.kt)("inlineCode",{parentName:"p"},"System.ts")," and be in the ",(0,r.kt)("inlineCode",{parentName:"p"},"/src/systems")," folder.\nThis is to optimize vite's code-splitting bundling process, as each potentially dynamically\nimportable file will result in a new bundle with it's own copy of all of it's import dependencies."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"@etherealengine/*")," monorepo dependencies will be symlinked and not needed, but some\npackage managers (such as pnpm) require these to be defined. If so, they should\nbe defined in ",(0,r.kt)("inlineCode",{parentName:"p"},"peerDependencies")," and kept up to date with the current engine version."),(0,r.kt)("h2",{id:"config"},"Config"),(0,r.kt)("p",null,"The ethereal engine config file has the following options:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"export interface ProjectConfigInterface {\n onEvent?: string\n thumbnail?: string\n routes?: {\n [route: string]: {\n component: () => Promise<{ default: (props: any) => JSX.Element }>\n props?: {\n [x: string]: any\n exact?: boolean\n }\n }\n }\n webappInjection?: () => Promise<{ default: (props: any) => void | JSX.Element }>\n worldInjection?: () => Promise<{ default: () => Promise<void> }>\n services?: string\n databaseSeed?: string\n settings?: Array<ProjectSettingSchema>\n}\n")),(0,r.kt)("h3",{id:"hooks"},"Hooks"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"onEvent")," property is a relative path string that points to a file which\nmust expose an object with properties as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"export interface ProjectEventHooks {\n onInstall?: (app: Application) => Promise<any>\n onLoad?: (app: Application) => Promise<any>\n onUpdate?: (app: Application) => Promise<any>\n onUninstall?: (app: Application) => Promise<any>\n /**\n * get oEmbed for active routes that match URL\n * return that project's onOEmbedRequest()\n * if null, return default\n */\n onOEmbedRequest?: (app: Application, url: URL, currentOEmbed: OEmbed) => Promise<OEmbed | null>\n}\n")),(0,r.kt)("p",null,"These functions are called when the project they belong to are installed,\nupdated (such as scenes saved) or uninstalled respectively. This is used in the\ndefault ethereal engine project to install the default avatars.\nSee ",(0,r.kt)("inlineCode",{parentName:"p"},"/packages/projects/default-project/projectEventHooks.ts"),"."),(0,r.kt)("h3",{id:"thumbnail"},"Thumbnail"),(0,r.kt)("p",null,"This is a URL to a thumbnail for the project."),(0,r.kt)("h3",{id:"routes"},"Routes"),(0,r.kt)("p",null,"Routes enable users to customise the various URL paths of their website\nutilising dynamic loading of modules. The key of each object represents the path\n(with leading forward slash included) while the value represents a react\ncomponent object which gets wrapped in ",(0,r.kt)("inlineCode",{parentName:"p"},"React.lazy()")," and a props object which\npasses options into the react-dom-router Route component corresponding to the route."),(0,r.kt)("h3",{id:"webapp-injection"},"Webapp Injection"),(0,r.kt)("p",null,"Webapp injection allows logic to be run on all pages, loaded before any routes\nare loaded. This will soon be extended to allow easy stylesheet injection and\nother configurables of the webapp."),(0,r.kt)("h3",{id:"world-injection"},"World Injection"),(0,r.kt)("p",null,"World injection allows logic to be run every time a new world is created,\ncurrently only when the engine is initialised. This is loaded on all instances\nof the engine, such as a location and the editor. An example use case of this\nwould be registering custom scene loader and editor prefabs."),(0,r.kt)("h3",{id:"services"},"Services"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"services")," property is a relative path that points to a file which must\nreturn type ",(0,r.kt)("inlineCode",{parentName:"p"},"((app: Application) => Promise<any>)[]")," which is run on all\ninstanceservers and api servers at startup. This allows users to expose custom\nFeathers services, or whatever other functionality they made need."),(0,r.kt)("h3",{id:"database-seeding"},"Database Seeding"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"databaseSeed")," property is a relative path that points to a file which must\nreturn type ",(0,r.kt)("inlineCode",{parentName:"p"},"ServicesSeedConfig")," from ",(0,r.kt)("inlineCode",{parentName:"p"},"../packages/common/src/interfaces/ServicesSeedConfig.ts"),"\nwhich is run when the database seeder is run."),(0,r.kt)("h3",{id:"i18n"},"i18n"),(0,r.kt)("p",null,"Internationalization can be added using the pattern ",(0,r.kt)("inlineCode",{parentName:"p"},"./i18n/<language>/<namespace>.json"),". An example of the format can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/tree/dev/packages/client-core/i18n"},"the base i18n files"),"."))}u.isMDXComponent=!0},8098:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png"}}]); \ No newline at end of file diff --git a/assets/js/4a62c6ed.61dce0d2.js b/assets/js/4a62c6ed.61dce0d2.js new file mode 100644 index 000000000000..16ae843bbc70 --- /dev/null +++ b/assets/js/4a62c6ed.61dce0d2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5624],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 c(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,c(c({ref:t},s),{},{components:r})):n.createElement(f,c({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var p=2;p<a;p++)c[p]=r[p];return n.createElement.apply(null,c)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},8510:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={},c="Development",i={unversionedId:"creator/development/readme",id:"creator/development/readme",title:"Development",description:"In this section you will find out how to create your own projects with Ethereal Engine.",source:"@site/docs/2_creator/4_development/readme.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/",permalink:"/etherealengine-docs/docs/creator/development/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Asset Import Pipeline",permalink:"/etherealengine-docs/docs/creator/importing_assets/"},next:{title:"Projects",permalink:"/etherealengine-docs/docs/creator/development/projects_overview"}},l={},p=[],s={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"development"},"Development"),(0,o.kt)("p",null,"In this section you will find out how to create your own projects with Ethereal Engine."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4b422948.50ee1827.js b/assets/js/4b422948.50ee1827.js new file mode 100644 index 000000000000..19b0a860aacc --- /dev/null +++ b/assets/js/4b422948.50ee1827.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3881],{3905:(e,A,t)=>{t.d(A,{Zo:()=>p,kt:()=>h});var a=t(7294);function n(e,A,t){return A in e?Object.defineProperty(e,A,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[A]=t,e}function o(e,A){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);A&&(a=a.filter((function(A){return Object.getOwnPropertyDescriptor(e,A).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var A=1;A<arguments.length;A++){var t=null!=arguments[A]?arguments[A]:{};A%2?o(Object(t),!0).forEach((function(A){n(e,A,t[A])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(A){Object.defineProperty(e,A,Object.getOwnPropertyDescriptor(t,A))}))}return e}function l(e,A){if(null==e)return{};var t,a,n=function(e,A){if(null==e)return{};var t,a,n={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],A.indexOf(t)>=0||(n[t]=e[t]);return n}(e,A);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],A.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var r=a.createContext({}),s=function(e){var A=a.useContext(r),t=A;return e&&(t="function"==typeof e?e(A):i(i({},A),e)),t},p=function(e){var A=s(e.components);return a.createElement(r.Provider,{value:A},e.children)},w="mdxType",c={inlineCode:"code",wrapper:function(e){var A=e.children;return a.createElement(a.Fragment,{},A)}},u=a.forwardRef((function(e,A){var t=e.components,n=e.mdxType,o=e.originalType,r=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),w=s(t),u=n,h=w["".concat(r,".").concat(u)]||w[u]||c[u]||o;return t?a.createElement(h,i(i({ref:A},p),{},{components:t})):a.createElement(h,i({ref:A},p))}));function h(e,A){var t=arguments,n=A&&A.mdxType;if("string"==typeof e||n){var o=t.length,i=new Array(o);i[0]=u;var l={};for(var r in A)hasOwnProperty.call(A,r)&&(l[r]=A[r]);l.originalType=e,l[w]="string"==typeof e?e:n,i[1]=l;for(var s=2;s<o;s++)i[s]=t[s];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}u.displayName="MDXCreateElement"},3825:(e,A,t)=>{t.r(A),t.d(A,{assets:()=>m,contentTitle:()=>D,default:()=>b,frontMatter:()=>k,metadata:()=>f,toc:()=>E});var a=t(7462),n=(t(7294),t(3905));const o={toc:[]},i="wrapper";function l(e){let{components:A,...t}=e;return(0,n.kt)(i,(0,a.Z)({},o,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this step, you need to provide sudo password for linux terminal. This is because Control Center App will perform various actions on your system with admin privileges."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Windows, this is the password of your WSL Ubuntu distribution's sudo user.")))}l.isMDXComponent=!0;const r={toc:[]},s="wrapper";function p(e){let{components:A,...t}=e;return(0,n.kt)(s,(0,a.Z)({},r,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this step, you will need to provide following information:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Engine Path:")," This is the location of ethereal engine source code repo. If the path does not contain the source code, then it will be ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine"},"cloned")," by Control Center App."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"On Windows, the path must be inside WSL Ubuntu distribution."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Ops Path:")," This is the location of ethereal engine ops source code repo. If the path does not contain the source code, then it will be ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"cloned")," by Control Center App."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"On Windows, the path must be inside WSL Ubuntu distribution."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Enable Ripple Stack:")," By default you should keep this option as off unless you want to have IPFS & rippled server running in your local K8s deployment.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Force DB Refresh:")," This will truncate database tables & repopulate them with seed data."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"If the database is empty, then Control Center App will itself force populate it.")))))}p.isMDXComponent=!0;const w={toc:[]},c="wrapper";function u(e){let{components:A,...t}=e;return(0,n.kt)(c,(0,a.Z)({},w,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this step for most of the users, go with the default variable values and leave the text fields as it is."),(0,n.kt)("p",null,"For advanced setup, if you want to configure oAuth, S3 file storage, email, SMS support then you can provide variable values."))}u.isMDXComponent=!0;const h={toc:[]},g="wrapper";function d(e){let{components:A,...t}=e;return(0,n.kt)(g,(0,a.Z)({},h,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"This step will show a summary of all the previous steps. User can review them before proceeding ahead."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Please make sure to read ",(0,n.kt)("inlineCode",{parentName:"p"},"Note")," on this screen.")),(0,n.kt)("p",null,"Afterwards, there are following option(s):"))}d.isMDXComponent=!0;const k={hide_table_of_contents:!0},D="Getting Started",f={unversionedId:"host/devops_deployment/tutorials/ethereal_control_center/getting_started",id:"host/devops_deployment/tutorials/ethereal_control_center/getting_started",title:"Getting Started",description:"The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster.",source:"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/01_getting_started.md",sourceDirName:"1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center",slug:"/host/devops_deployment/tutorials/ethereal_control_center/getting_started",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/01_getting_started.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Control Center App",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/"},next:{title:"Ethereal Engine Admin Panel Guide",permalink:"/etherealengine-docs/docs/host/Admin_Dashboard/"}},m={},E=[{value:"App Overview",id:"app-overview",level:2},{value:"1. Downloading Control Center App",id:"1-downloading-control-center-app",level:2},{value:"2. Launch & Create Cluster",id:"2-launch--create-cluster",level:2},{value:"2.1. Cluster Information",id:"21-cluster-information",level:3},{value:"2.2. Cluster Type: MicroK8s or Minikube",id:"22-cluster-type-microk8s-or-minikube",level:3},{value:"2.2.1. Authentication",id:"221-authentication",level:3},{value:"2.2.2. Configurations",id:"222-configurations",level:3},{value:"2.2.3. Variables",id:"223-variables",level:3},{value:"2.2.4. Summary",id:"224-summary",level:3},{value:"2.3. Cluster Type: Custom",id:"23-cluster-type-custom",level:3},{value:"2.3.1. Kubeconfig",id:"231-kubeconfig",level:3},{value:"2.3.2. Deployment",id:"232-deployment",level:3},{value:"2.3.3. Summary",id:"233-summary",level:3},{value:"3. Cluster Screen",id:"3-cluster-screen",level:2},{value:"3.1. Hotbar",id:"31-hotbar",level:3},{value:"3.2. Navbar",id:"32-navbar",level:3},{value:"3.3. Options Panel",id:"33-options-panel",level:3},{value:"3.4. System Status",id:"34-system-status",level:3},{value:"3.5. Apps Status",id:"35-apps-status",level:3},{value:"3.6. Engine Status",id:"36-engine-status",level:3},{value:"3.7. Logs",id:"37-logs",level:3},{value:"4. Configure Cluster",id:"4-configure-cluster",level:2},{value:"4.1. Authentication",id:"41-authentication",level:3},{value:"4.2. Configurations",id:"42-configurations",level:3},{value:"4.3. Variables",id:"43-variables",level:3},{value:"4.4. Summary",id:"44-summary",level:3},{value:"5. Launch Ethereal Engine",id:"5-launch-ethereal-engine",level:2},{value:"6. Workloads",id:"6-workloads",level:2},{value:"6.1. Workload Tabs",id:"61-workload-tabs",level:3},{value:"6.2. Workloads Table",id:"62-workloads-table",level:3},{value:"6.3. Workload Logs",id:"63-workload-logs",level:3},{value:"7. Admin Dashboard",id:"7-admin-dashboard",level:2},{value:"8. K8 Dashboard",id:"8-k8-dashboard",level:2},{value:"9. IPFS",id:"9-ipfs",level:2},{value:"10. Rippled CLI",id:"10-rippled-cli",level:2},{value:"11. Updating the App",id:"11-updating-the-app",level:2}],B={toc:E},M="wrapper";function b(e){let{components:A,...o}=e;return(0,n.kt)(M,(0,a.Z)({},B,o,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"getting-started"},"Getting Started"),(0,n.kt)("p",null,"The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster."),(0,n.kt)("p",null,"We know it's been complicated to build with Ethereal Engine and we've made this tool to give the community easy access to the engine. We would love to see your creations and invite you all to come build with us."),(0,n.kt)("h2",{id:"app-overview"},"App Overview"),(0,n.kt)("p",null,"The Ethereal Engine Control Center app provides access to various functionalities which includes:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Configure your Ethereal Engine in a cluster in just a few clicks."),(0,n.kt)("li",{parentName:"ul"},"View status of Ethereal Engine dependencies on your local system."),(0,n.kt)("li",{parentName:"ul"},"Manage an Ethereal Engine deployment through admin panel."),(0,n.kt)("li",{parentName:"ul"},"Manage kubernetes cluster through its dashboard."),(0,n.kt)("li",{parentName:"ul"},"Manage IPFS node running in the cluster."),(0,n.kt)("li",{parentName:"ul"},"Execute commands against rippled server."),(0,n.kt)("li",{parentName:"ul"},"See realtime logs of different actions being performed.")),(0,n.kt)("h2",{id:"1-downloading-control-center-app"},"1. Downloading Control Center App"),(0,n.kt)("p",null,"In order to download Ethereal Engine Control Center App, navigate to ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine-control-center/releases"},"releases")," page and download the latest version of the App. On Windows (and for WSL), you will need to download ",(0,n.kt)("inlineCode",{parentName:"p"},".exe")," while for linux download ",(0,n.kt)("inlineCode",{parentName:"p"},"AppImage"),"."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Windows, you will need to allow permission for executing ps1 scripts. You can do so by running following command in Powershell with admin privileges (",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine-control-center#2-windows-permission-to-run-ps1-scripts"},"reference"),")."),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-Powershell"},"Set-ExecutionPolicy -ExecutionPolicy Unrestricted\n"))),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Linux, once downloaded, right click and go to ",(0,n.kt)("strong",{parentName:"p"},"Properties")," of AppImage. In ",(0,n.kt)("strong",{parentName:"p"},"Permissions")," tab check 'Allow executing file as program'. Afterwards, double click on AppImage to launch the app.")),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Ubuntu 22.04 or later, if you are unable to launch AppImage then you might have to install Fuse using following command in terminal (",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine-control-center#1-app-not-launching-in-ubuntu-2204"},"reference"),")."),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get install fuse libfuse2\n"))),(0,n.kt)("h2",{id:"2-launch--create-cluster"},"2. Launch & Create Cluster"),(0,n.kt)("p",null,"When you launch the app for the first time, you will see below screen:"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Home Screen",src:t(8370).Z,width:"1919",height:"1001"})),(0,n.kt)("p",null,"Here you need to create a cluster. You can do so by clicking on ",(0,n.kt)("inlineCode",{parentName:"p"},"Create")," button in the center or anytime using round plus button on left bottom corner (in ",(0,n.kt)("a",{parentName:"p",href:"#31-hotbar"},"hotbar"),") of the screen. Following are the different sections of create cluster dialog:"),(0,n.kt)("h3",{id:"21-cluster-information"},"2.1. Cluster Information"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Cluster Information",src:t(453).Z,width:"596",height:"552"})),(0,n.kt)("p",null,"In this step, you will need to provide following information:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Name:")," This can be any name you want to give your cluster. i.e. Local, my-metaverse, etc.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Type:")," This will be the kubernetes distribution you want to use. Currently there are 2 local distributions, MicroK8s(recommended) & Minikube. There is also a Custom type which allows you to connect to an existing Ethereal Engine cluster."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Currently, ",(0,n.kt)("inlineCode",{parentName:"p"},"MicroK8s")," is supported on Windows & Linux while ",(0,n.kt)("inlineCode",{parentName:"p"},"Minikube")," is supported on Linux only."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Prerequisites:")," These are the set of items that should be manually configured by the user. If an item is correctly setup then its status will be green tick, else it will have a red cross with details and link to docs for the corrective measures."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Currently, there are prerequisites for MicroK8s in Windows only.")))),(0,n.kt)("h3",{id:"22-cluster-type-microk8s-or-minikube"},"2.2. Cluster Type: MicroK8s or Minikube"),(0,n.kt)("p",null,"If you selected cluster type as MicroK8s or Minikube, then you will see below options."),(0,n.kt)("h3",{id:"221-authentication"},"2.2.1. Authentication"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Authentication",src:t(2569).Z,width:"597",height:"580"})),(0,n.kt)(l,{mdxType:"StepAuthentication"}),(0,n.kt)("h3",{id:"222-configurations"},"2.2.2. Configurations"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Configurations",src:t(4910).Z,width:"597",height:"553"})),(0,n.kt)(p,{mdxType:"StepConfigurations"}),(0,n.kt)("h3",{id:"223-variables"},"2.2.3. Variables"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Variables",src:t(4890).Z,width:"599",height:"554"})),(0,n.kt)(u,{mdxType:"StepVariables"}),(0,n.kt)("h3",{id:"224-summary"},"2.2.4. Summary"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Summary",src:t(2343).Z,width:"594",height:"695"})),(0,n.kt)(d,{mdxType:"StepSummary"}),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Create:")," By default you should go with this option as it will create the cluster entry and show the ",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"cluster screen")," of this cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Create & Configure:")," This will create the cluster entry and show the current status of things. And afterwards it will automatically start the configuration script to ensure things are setup."))),(0,n.kt)("blockquote",null,(0,n.kt)("blockquote",{parentName:"blockquote"},(0,n.kt)("p",{parentName:"blockquote"},"If you use 'Create' option, then you can still run the Configure script as discussed later in this ",(0,n.kt)("a",{parentName:"p",href:"#4-configure-cluster"},"guide"),"."))),(0,n.kt)("h3",{id:"23-cluster-type-custom"},"2.3. Cluster Type: Custom"),(0,n.kt)("p",null,"If you selected Custom cluster type, then you will see below options. Custom cluster allows to connect to an existing kubernetes cluster."),(0,n.kt)("h3",{id:"231-kubeconfig"},"2.3.1. Kubeconfig"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Kubeconfig",src:t(9611).Z,width:"594",height:"546"})),(0,n.kt)("p",null,"In this step, you will need to provide following information regarding desired cluster's kubeconfig:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config Type - Default:")," This will load the default kubeconfig file of your system.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config Type - File:")," This will allow to load kubeconfig from a file of your system.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config Type - Text:")," This will allow to load kubeconfig from a text.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Context:")," This is the selected kube context of cluster in which your ethereal engine deployment exists. The dropdown will show all contexts that exist in selected config type."))),(0,n.kt)("h3",{id:"232-deployment"},"2.3.2. Deployment"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Deployment",src:t(9015).Z,width:"596",height:"547"})),(0,n.kt)("p",null,"In this step, you will need to provide following deployment information:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Release Name:")," This is the name of your release in selected kubernetes deployment. It can be 'dev', 'prod', 'local', etc.",(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Release name is used to prefix the workloads in your cluster like:\n",(0,n.kt)("inlineCode",{parentName:"p"},"{RELEASE_NAME}-etherealengine-client"),". i.e. ",(0,n.kt)("inlineCode",{parentName:"p"},"prod-etherealengine-client"))))),(0,n.kt)("h3",{id:"233-summary"},"2.3.3. Summary"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Summary",src:t(5847).Z,width:"595",height:"545"})),(0,n.kt)(d,{mdxType:"StepSummary"}),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Create:")," This option will create the cluster entry and show the ",(0,n.kt)("a",{parentName:"li",href:"#6-workloads"},"workloads screen")," of this cluster.")),(0,n.kt)("h2",{id:"3-cluster-screen"},"3. Cluster Screen"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Cluster Screen",src:t(8682).Z,width:"1916",height:"1005"})),(0,n.kt)("p",null,"Once you have created a cluster you will be navigated to its screen also know as config page. Lets explain various sections of this screen:"),(0,n.kt)("h3",{id:"31-hotbar"},"3.1. Hotbar"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Hotbar",src:t(6290).Z,width:"97",height:"323"})),(0,n.kt)("p",null,"It will show you a list of all clusters you have created. You can click on each of them to view the cluster screen of them."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Add Cluster Icon",src:t(380).Z,width:"29",height:"29"})," The plus icon at the bottom of this bar is used to create a new cluster."),(0,n.kt)("h3",{id:"32-navbar"},"3.2. Navbar"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Navbar",src:t(1977).Z,width:"983",height:"70"})),(0,n.kt)("p",null,"This section allows navigation and various utility options. Following are the various options in it:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"App Icon:")," ",(0,n.kt)("img",{alt:"App Icon",src:t(8e3).Z,width:"152",height:"36"})," Logo of this application.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Home Icon:")," ",(0,n.kt)("img",{alt:"Home Icon",src:t(6072).Z,width:"46",height:"28"})," Navigate to home.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config:")," Navigates to ",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"cluster")," screen of selected cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Workloads:")," Navigates to ",(0,n.kt)("a",{parentName:"p",href:"#6-workloads"},"workloads")," screen of selected cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Admin:")," Navigates to ethereal engine ",(0,n.kt)("a",{parentName:"p",href:"#7-admin-dashboard"},"admin")," panel of selected cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"K8 Dashboard:")," Navigates to kubernetes ",(0,n.kt)("a",{parentName:"p",href:"#8-k8-dashboard"},"web dashboard")," of selected kubernetes distribution.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"IPFS:")," Navigates to IPFS ",(0,n.kt)("a",{parentName:"p",href:"#9-ipfs"},"web UI")," of selected cluster. This option is visible only if ripple stack is enabled.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Rippled CLI:")," Navigates to rippled ",(0,n.kt)("a",{parentName:"p",href:"#10-rippled-cli"},"server cli")," of selected cluster. This option is visible only if ripple stack is enabled.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Change Theme Icon:")," ",(0,n.kt)("img",{alt:"Change Theme Icon",src:t(2764).Z,width:"49",height:"30"})," Allows to toggle between vaporware, light & dark themes. The color scheme of these themes are similar to ethereal engine.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Support Icon:")," ",(0,n.kt)("img",{alt:"Support Icon",src:t(9026).Z,width:"46",height:"28"})," Opens a dropdown menu to allow reaching out to support via Discord or Github.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"User Icon:")," ",(0,n.kt)("img",{alt:"User Icon",src:t(6424).Z,width:"49",height:"29"})," The functionality for this button is coming soon."))),(0,n.kt)("h3",{id:"33-options-panel"},"3.3. Options Panel"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Options Panel",src:t(807).Z,width:"1212",height:"72"})),(0,n.kt)("p",null,"This section shows various actions against currently selected cluster. Following are the options in it:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Icon:")," ",(0,n.kt)("img",{alt:"Cluster Icon",src:t(8082).Z,width:"27",height:"26"})," Logo of the selected cluster type. It can be MicroK8s or Minikube logo.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Name:")," This is the cluster name that you entered in create cluster dialog. i.e. Local.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Engine Git Status:")," ",(0,n.kt)("img",{alt:"Cluster Icon",src:t(2383).Z,width:"133",height:"28"})," This is used to view current status of local ethereal engine github repo. You can view & change current branch, view & pull incoming changes, view & push outgoing changes.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Ops Git Status:")," ",(0,n.kt)("img",{alt:"Cluster Icon",src:t(4601).Z,width:"137",height:"28"})," This is used to view current status of local ethereal engine ops github repo. You can perform all actions as explained for engine git status.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Refresh Icon:")," ",(0,n.kt)("img",{alt:"Refresh Icon",src:t(9662).Z,width:"31",height:"26"})," This will recheck the status of prerequisites, system, apps & engine. It also, recheck the status of engine and ops git repos. If a refresh is already in process then it will be disabled until its finished.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Delete Icon:")," ",(0,n.kt)("img",{alt:"Delete Icon",src:t(5987).Z,width:"26",height:"26"})," This will delete a clusters. It would not make any changes in associated local kubernetes, app, etc.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Settings Icon:")," ",(0,n.kt)("img",{alt:"Settings Icon",src:t(7697).Z,width:"30",height:"26"})," This will open settings dialog. It contains some selected cluster specific settings in addition to general app settings.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Configure Button:")," ",(0,n.kt)("img",{alt:"Configure Button",src:t(5401).Z,width:"85",height:"36"})," This will open the configure dialog which is ",(0,n.kt)("a",{parentName:"p",href:"#4-configure-cluster"},"discussed")," later. If a configuration is already running then this button will be disabled and have a spinner in it.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Launch Button:")," ",(0,n.kt)("img",{alt:"Launch Button",src:t(3377).Z,width:"65",height:"36"})," This button will open Ethereal Engine's default location in your browser as ",(0,n.kt)("a",{parentName:"p",href:"#5-launch-ethereal-engine"},"discussed")," later."))),(0,n.kt)("h3",{id:"34-system-status"},"3.4. System Status"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"System Status",src:t(1412).Z,width:"1793",height:"133"})),(0,n.kt)("p",null,"This section will show the current status of whether the system requirements are meet or not. On Windows, it will also show the status of prerequisites."),(0,n.kt)("p",null,"The status against each item will be displayed. You can find more details by hovering over ",(0,n.kt)("img",{alt:"Info Icon",src:t(5048).Z,width:"25",height:"24"})," info icon. This info icon is useful when some item is not configured correctly."),(0,n.kt)("p",null,"Additionally, for some items you will see ",(0,n.kt)("img",{alt:"Fix Icon",src:t(5071).Z,width:"28",height:"29"})," auto fix icon. Clicking this button will try to auto fix the problem. Though if it fails, you can try using configure dialog which is ",(0,n.kt)("a",{parentName:"p",href:"#4-configure-cluster"},"discussed")," later."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Usually, auto fix button should only be used if previously you were able to run the cluster successfully. Otherwise, use configure dialog.")),(0,n.kt)("h3",{id:"35-apps-status"},"3.5. Apps Status"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Apps Status",src:t(790).Z,width:"1788",height:"255"})),(0,n.kt)("p",null,"This section will show the current status of all the apps required to run ethereal engine deployment."),(0,n.kt)("h3",{id:"36-engine-status"},"3.6. Engine Status"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Engine Status",src:t(7164).Z,width:"1791",height:"97"})),(0,n.kt)("p",null,"This section will show the current status of various components of ethereal engine deployment in your local kubernetes distribution."),(0,n.kt)("h3",{id:"37-logs"},"3.7. Logs"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Logs",src:t(8121).Z,width:"1792",height:"252"})),(0,n.kt)("p",null,"This section will show all the logs of current session. The logs are of the different actions being performed by control center and their output."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Download Button:")," ",(0,n.kt)("img",{alt:"Download Button",src:t(4783).Z,width:"28",height:"33"})," This will download all displayed logs.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Clear Button:")," ",(0,n.kt)("img",{alt:"Clear Button",src:t(2038).Z,width:"31",height:"33"})," This will clear all displayed logs."))),(0,n.kt)("h2",{id:"4-configure-cluster"},"4. Configure Cluster"),(0,n.kt)("p",null,"On (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"cluster screen"),"), if any of the status is not green tick then it means you need to run the configure script to fix them automatically. To do so use the Configure (",(0,n.kt)("img",{alt:"Configure Button",src:t(5401).Z,width:"85",height:"36"}),") button in the ",(0,n.kt)("a",{parentName:"p",href:"#33-options-panel"},"options panel"),". Following are the different sections of configure cluster dialog:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Its always recommended to clear your logs before running configure script in order to trace outputs easily.")),(0,n.kt)("h3",{id:"41-authentication"},"4.1. Authentication"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Authentication",src:t(9478).Z,width:"596",height:"576"})),(0,n.kt)(l,{mdxType:"StepAuthentication"}),(0,n.kt)("h3",{id:"42-configurations"},"4.2. Configurations"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Configurations",src:t(2725).Z,width:"594",height:"544"})),(0,n.kt)(p,{mdxType:"StepConfigurations"}),(0,n.kt)("h3",{id:"43-variables"},"4.3. Variables"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Variables",src:t(9757).Z,width:"594",height:"594"})),(0,n.kt)(u,{mdxType:"StepVariables"}),(0,n.kt)("h3",{id:"44-summary"},"4.4. Summary"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Summary",src:t(2718).Z,width:"600",height:"687"})),(0,n.kt)(d,{mdxType:"StepSummary"}),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Configure:")," This will start the configuration script which will ensure things are setup. You can track output of various things in ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs"),". Depending on your system and status of apps, it can take a while to setup things. As the configure script is executing, the Configure (",(0,n.kt)("img",{alt:"Configure Button",src:t(5401).Z,width:"85",height:"36"}),") button will be disabled and have a spinner in it."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Once the script finished its execution, the cluster status will be automatically refreshed.")),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"If the configure script failed, pay close attention to last few lines of ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs")," section. As it will contain the reason why script failed.")))),(0,n.kt)("h2",{id:"5-launch-ethereal-engine"},"5. Launch Ethereal Engine"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Launch Ethereal Engine",src:t(4832).Z,width:"1919",height:"930"})),(0,n.kt)("p",null,"Once, everything is configured correctly and all ticks are green on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"Launch")," button in ",(0,n.kt)("a",{parentName:"p",href:"#33-options-panel"},"options panel"),". This button will open Ethereal Engine's default location in your browser."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Make sure to allow certificates as explained ",(0,n.kt)("a",{parentName:"p",href:"https://etherealengine.github.io/etherealengine-docs/docs/devops_deployment/microk8s_linux#accept-invalid-certs"},"here"),".")),(0,n.kt)("h2",{id:"6-workloads"},"6. Workloads"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workloads",src:t(7317).Z,width:"1920",height:"992"})),(0,n.kt)("p",null,"This page will show current state of workloads for selected cluster. The workloads are mainly the k8s pods of various components of ethereal engine. In addition to ",(0,n.kt)("a",{parentName:"p",href:"#33-options-panel"},"options panel"),", following the sections of this screen:"),(0,n.kt)("h3",{id:"61-workload-tabs"},"6.1. Workload Tabs"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workload Tabs",src:t(1623).Z,width:"1195",height:"104"})),(0,n.kt)("p",null,"This section allows to filter based on various workload types. Default tab will be ",(0,n.kt)("inlineCode",{parentName:"p"},"All"),", which displays all workloads. The number below each tab's label will display the currently ready count followed by slash and then total count."),(0,n.kt)("h3",{id:"62-workloads-table"},"6.2. Workloads Table"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workloads Table",src:t(6490).Z,width:"1788",height:"377"})),(0,n.kt)("p",null,"This section will display data based on selected workload ",(0,n.kt)("a",{parentName:"p",href:"#61-workload-tabs"},"tab"),". For each workload, it will contain pod name and other details. Hovering over a container's circle will display further details. Moreover, there is a ",(0,n.kt)("inlineCode",{parentName:"p"},"Logs")," button to view kubernetes container logs as discussed in next ",(0,n.kt)("a",{parentName:"p",href:"#63-workload-logs"},"section"),". ",(0,n.kt)("inlineCode",{parentName:"p"},"Delete")," button will allow to remove the pod from current kubernetes distribution."),(0,n.kt)("p",null,"Additionally, there is refresh icon button on right top of this table. This will refresh/reload data being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval."),(0,n.kt)("h3",{id:"63-workload-logs"},"6.3. Workload Logs"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workload Logs",src:t(6200).Z,width:"1804",height:"205"})),(0,n.kt)("p",null,"This section will by default display cluster ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs"),". Though if user clicked ",(0,n.kt)("inlineCode",{parentName:"p"},"Logs")," button as discussed in previous ",(0,n.kt)("a",{parentName:"p",href:"#62-workloads-table"},"section"),", then the logs of that workload will be displayed. The cluster ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs")," will then be displayed under ",(0,n.kt)("inlineCode",{parentName:"p"},"Config")," log tab. User can toggle between these log tabs, while workload logs can be closed as well."),(0,n.kt)("p",null,"The download and clear icon button will perform actions based on selected log's tab. Additionally for workload logs, there is refresh icon button on right top of this section. This will refresh/reload logs being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval."),(0,n.kt)("p",null,"Beside these icons there is also a container drop down through which user can select the workload's pod container for which logs are displayed."),(0,n.kt)("h2",{id:"7-admin-dashboard"},"7. Admin Dashboard"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Admin Dashboard",src:t(1089).Z,width:"1920",height:"1012"})),(0,n.kt)("p",null,"Once, everything is configured correctly and all ticks are green on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"Admin")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the admin dashboard of ethereal engine deployed in your local k8s cluster."),(0,n.kt)("p",null,"You can perform various actions from admin dashboard including installing projects, managing users, groups, locations, instances, resources, etc."),(0,n.kt)("h2",{id:"8-k8-dashboard"},"8. K8 Dashboard"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"K8 Dashboard",src:t(9593).Z,width:"1919",height:"1004"})),(0,n.kt)("p",null,"Once, your selected local k8s distribution (Microk8s or Minikube) has a green tick on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"K8 Dashboard")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the k8s dashboard."),(0,n.kt)("p",null,"For MicroK8s, when you launch it for the first time then you will be asked regarding token configurations. You can use ",(0,n.kt)("inlineCode",{parentName:"p"},"Skip")," button to pass through it."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"K8 Dashboard Token",src:t(7728).Z,width:"1437",height:"336"})),(0,n.kt)("p",null,"You can perform various actions from k8s dashboard including managing pods, jobs, deployments, services, etc."),(0,n.kt)("h2",{id:"9-ipfs"},"9. IPFS"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"IPFS Web UI",src:t(8625).Z,width:"1919",height:"1009"})),(0,n.kt)("p",null,"If ripple stack is enabled and once, IPFS has a green tick on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"IPFS")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the IPFS web UI."),(0,n.kt)("p",null,"You can view and manage various aspects of the IPFS running in your local cluster using this dashboard. IPFS is not required by default for engine, though for custom use cases it can be used."),(0,n.kt)("h2",{id:"10-rippled-cli"},"10. Rippled CLI"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Rippled CLI",src:t(7083).Z,width:"1918",height:"1007"})),(0,n.kt)("p",null,"If ripple stack is enabled and once, Rippled has a green tick on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"Rippled CLI")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the Rippled CLI page."),(0,n.kt)("p",null,"You can run various commands against ",(0,n.kt)("inlineCode",{parentName:"p"},"rippled")," server and view their outputs. Rippled is not required by default for engine, though for custom use cases it can be used."),(0,n.kt)("h2",{id:"11-updating-the-app"},"11. Updating the App"),(0,n.kt)("p",null,"Every time you launch control center app it will check for the latest version of the app. If there is an update, then it will prompt to update. Its always recommend to use the latest version of the app."))}b.isMDXComponent=!0},1089:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg"},8682:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg"},9478:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg"},2725:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg"},9757:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg"},2718:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg"},453:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg"},2569:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg"},4910:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg"},4890:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg"},2343:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg"},9611:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg"},9015:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg"},5847:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg"},4832:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg"},8370:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg"},380:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAdAB0DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD84f2RP2Tf+Gk73xRrXiDxRa/D/wCGPw7s4tQ8YeLLq1a7XTI5XKQW1vApBuLy4dWWKEMM7WY8Lg9/qX7ZnwN+GUj6X8Nf2XfButaNASq6z8UtXvtc1zUwCQJZYrSe2trUsMExR+YFOcOQRhn7Sl63w2/4Jlfsz+DtNZ4bHx1e+I/iJr23AXUb1btdMsg/HJtreCdVBPAuegPNXv8Agmr+whB+058Q7C/13VvhrN4auNM10f2RqPjG10/VTcQabdPbym1MizLGs6xyFyAu2NmPyg1+gVJxlGVau3yptJXtt6btv5Gepa8Hal+zz+3brkPhS+8I6T+y78RtVkWDQ/EmkapdX/gnUbpuEtdRs7gtNYK7bVW6hlkVC2XQKuG+a/ir8K/EXwN+KPiLwV4s0q40XxP4T1CXTNUsZfvW08bYIBHDIRhkcZV0ZWBIYGrXxp+B2ofBHWLXRtW1rwT4ikvrIXJm8Na/ba3ZhGLLsaWBmRXypJTOQCOxr2j/AIKU69ceOfgX+y78Sr6S4uPFPjD4cnR9avJvnl1JtG1G60yC4lY5LytbwxBnJJYpkk1opexceR3jLo9bPfrr95O50nwO8GXH/BQf9hez+Enh9ftXxm+Bmo6l4k8IaSX/AH3jLw/qAjk1GwtVx895a3FvHcJHnLxSSBATux84/Br4wa58APiQ/iDQVtrfW7G11DSZI7623+Qt1bTWdwjxtgrII5XGDgqwGeRiuf0nXL7wprVlqulX19peq6bcJdWd9ZXL211ZzIQySxSoQ8cisAQykEEcEV9Iax/wVV1/x5DHP8XPhV8D/jZrFvEsK+IPE/hNYdeuVjUKouL6zeCS4wAB+93E9TkkmqlTnSbSSlCXTqr7+qfyHzJnjf7Nf7M/jH9rD4tWHgL4e6T/AGtr14nmSNIxjtdKtlwHu7uXkQW0YOXkbtwAWwD6J/wUb+LPhT4hfEvwr4E8A6g2sfDf4JeG7bwPoOqtH5Y8QyQNJJfaqq5bal1eSzyIMnKbCMAhQz41f8FF/iB8WPhVd+BdHsfBXwr+HGpSrLfeFvh7oEPh6z1cqny/bnizNeYHaaRlJ+YqWAI8LQGLKjjacfLx0ranRqTmqtVWS2S1+bYnpsf/2Q=="},6290:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAFDAGEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4t/4d7f8AU3f+Ur/7dR/w72/6m7/ylf8A26vpKiv7v/4h7kP/AD4/8ml/mfM/W63c+bf+He3/AFN3/lK/+3Uf8O9v+pu/8pX/ANur6Soo/wCIe5D/AM+P/Jpf5h9ar7nzb/w72/6m7/ylf/bqP+He3/U3f+Ur/wC3V9JdqGO3rx9aiXAPD0Piopespf8AyRUcRiHsfNv/AA72/wCpu/8AKV/9uo/4d7f9Td/5Sv8A7dX0lnNBOKI8AcPNcyoq3+KX+ZMsVXWjPm3/AId7f9Td/wCUr/7dR/w72/6m7/ylf/bq+kqK0/4h5kP/AD4/8ml/mH1qva582/8ADvb/AKm7/wApX/26j/h3t/1N3/lK/wDt1fSVFZ1PD3IVFtUP/Jpf5gsXW7n5N/8AC9f+oWf/AAL/APsKK4PFFfhf9l0e34s9T2j7n7QUUUV/Vh4IUdKKaQGf71flXjB4lUuCOHZ5o1zVJPkpx/mk+r8lu+9rH33hxwRV4pzeGDvamtZy/ur9XsvvEBYnp8rdCe9K43nDfMeuD27V7R+xl+xJ4h/bL8V6ha6XcRaRo+koGvtSki8xImbOyNVBUu5wf4uMHOK+lPhBcfsp/BPwFDpPxG0GH/hOtPmex1i0mhuL9lnjbY0iNjaI2wHwpH3vWv8AMLOOIuKeK68swzrGuFOWq5pOMUu0UnZW8kf2RGvw1wt/wm5Rg3WqwtzqnFSmr/zPfW2u9rrY+NfhF+zn43+PI1A+D/Dmo64ulp5l08AULEDkgbmIBY4OFBJOOBXI3dvNpt5Jb3UUlvcQuY5I5F2ujA4II6gg8Yr9aP2aL/SPCF94m1P9nux8NeMPCPiB0updLbUm0+50W7WMIcq8bN5Um0N8wyGztyCMfl/8dzrVz8a/GEviTT10vxBPrF1NqFoBhYJnlZnC/wCzkkgjggggkc19lwz4kcQcBSw+MwmLnWhKTU4SblTcVty30T7NO/5Hx/8AZeXcdYrFYHE4WFBxinBr3aqb3U49V3vp27nK0UyM84p9f6fcJ8TYTiDKKGb4H4KqTX5NP0ejP5B4gyTEZRmNXLsT8dNtevZ/MKKKK9+p8D9Dx0fi/RRRX81HsH7QUUUV/TB44V7l+wL+xk37a3xB1TSpNcXQtP0e0S5mlVPNmk3MUAVC2OgzkE44z1FeG1tfDf4o+JPhLr/9qeGda1DQ9SCGL7RaylGKHGVPJBHAPI7Cv4v+mDS5cJleMxMHOhGpNTS2vJLl/Jn9FeAcMRX/ALQwmXVVTxUoRcJPok3f9D9GLvVbr9gv9gr4qeEtEkX/AISLwpq4sP7Ygj2/ajepBItyT0WRIZVQgE7WjT1FfmdcXElxO0kzySzTNvd3Yl3J5OS3JJ9zX6N/8E/PF/h39s/9kXxt8JfE181v4qvJpb2e8mlDXGoM7h4rrceXaNkVT/sxpz83HxD4m/Zi8Z+H9TvksdB1bXtLtL6Wxh1TTrKWazvGjkKEo+3nBUg/Sv4j4so1MVh8LXwWtLlsktbO/W3ZWV/I/cvDjE4fLsZj8Hm1o4n2ilKctOZNKzTfd3aXn6mp+xd8ftQ/Zu/aH8O6/Yy3C2Ml1Hb6lbQIZPtduzYdCi8u4BLKMZBUEelek/8ABVP4g+F/ix8e9P8AE3h2z1qzm1PT1j1AajpU2ntJJGSiuBIqlsqQpIz90DrXb/8ABPD/AIJ/axbfFPR/HnxMiTwfoGh3K3dhaapKLa51K4XlPkcghFba3zAFsADIJrzn/gqD+0jp/wC0Z+01dNos32jQPDMX9l2cy4KXMisfOlXHVWI2j1CKR1rnqYfE4Th6VLFvlUpJxi99N3rt9x2UcZgMw44hVyyDk6dNqpOMvd12Tsvefz/I+cE/1jU+mxjc5p1f6Y/Rgw+JpeH+DWI+05tejm7ffv8AM/lfx0r0KvGGI9j9lRT9eVBRRRX9AVPgfofj5+L9FFFfzUewftBRRRX9MHjhTSMHd3p1FfHcd8E5fxXk9XJszXuTWj6xfSS9Hb12PpOE+KcZw/mNPM8E/ei9V/MnuvRoueGfE+peENYj1DR9RvNK1CEEJc2k7QSoCCDhlIOCCcjOOT6Cvq74A/8ABYHxd8B/hrYeF18I+G9TsNLiEFsyeZbsFHdgCQzMTknjJ5xXyG0Wfu/LSYZfQ/jX+dOefRz8QeHMXJZKvb0fsyi46rpeMtU/S68z+uafifwFxPhYvPI8lRWvGSktfKUeiu7beh+jP7Lf7aPwx/aW8VeNvEHxsj8M2up7Y4tLsdVjWa1tLLysMkHmA5dnLFyfmO5RyqgD4D+KNxot58TPEUnhuFofD02p3DaZGw2slqZWMSkdiEK+/FYRjYkZK4znv/8AW5+lKsaovH1/Gvs+Dfo3cU5/VoLiumsPRpy5m006k/JJOyT/AA7Hx2YeJPDXDVTEVeGZyrVKsVGMXdU4W0vqrtrf9Ry/LRRRX+gmVZXhsuwdPAYOPLTppKK7W29dN33P5fx2OrYyvLFYiXNUm7tv+v8AhgooortqfA/Q4z8X6KKK/mo9g/aCiiiv6YPHCjoce2fw9aK9e/ae8NaX4e+HXwem0/T7Kxm1PwiLi8kggSI3U32y4XzJNuN8mFA3Nk4A5rzcZmaw1ejRkr+0bj6WjKX6FUY88pLtG/8A5Ml+p5DigfMeOT2A7/T19fpzX2hqA8L/AA2/a18N/A//AIV74R1bwtMNP0XUL2XSEk1i+lu4Inku1u/9ZGyyT7gEIVFjOBXG+MtM0v8AZC+Avh2403w74V8Ua94p8Q6xbXWpa9pMOppDb6dcLbxwwxyhkRXyZCwy3OM4C4+To8cSqThRp0X7SryumnJWcZKTTk+jUYt213S726Pqvn/W/wDXmfMI5/PH+f5fWg8D04zzX1P8B/AuhfFf9pbxb460X4Z6hd+FfCmjHWl8JSWBvI7y9liVIrVYlDFoXnZ5VwuAiHIAGK1NS/Zy0v4a/tCfHHTrrQYf7Kb4fal4l0CG/sVR7BZjDJDtV1zHJFueEMAHDRsPlINOtx9haNV4eVN86hGTV43TbScfVKSb6O/kNYOUtV3t8j5EooYbRzwMZz2Ior7tSTRyBRRRSqfA/QD8X6KKK/mo9g/aCiiiv6W549zyLMK9Qvf2mE8QeD/Dej654D8F68PCun/2XZXd1LqkE4g3vJ8wt7yKNm3uxyUHWvL6K8/HZdhsYo+2Xwu8WpOLWlvstPZtDptxba6q3yunb70j27QP28PFGg2uk3B0HwXfeKdBsBpun+J7vTXk1e1iVGSIh/M8ppI1ICu8TMABkmud+H/7Umq+Dfh9/wAIvqmgeFvGmgxX/wDaVraeILaa4FjcMQZHjaKWJgHwNyMzKSOnLZ8zorzo8L5Tyyj7NLmad03dWu1yu94pXekbbtdTT2s/6+78vw0PTvib+1t4s+LXh7xFp2rDTFXxVrEGr39xbwNFK/kQ+VBaja237NGCSi7SwPJJyRWl4L/bR8QeEPD+naZNofhjWrbT/Dt74VZr+O68670+5mWZoZJIp42whBEZUqVVmGScEeP0U58M5RKj7CVGPKnfdqzty3VtdtLdkgjVqLb+tb/pf1Nzxz4t0/xZdwyaf4X0LwusKsHj0ua8kWYn+JjdTzNuHoCorDoor2sLThQpKlCXu+bcn/5NdkSuwoooq6k48j16Csz8X6KN1FfzZc9Y+jP+F3eNP+hu8T/+DSf/AOLo/wCF3eNP+hu8T/8Ag0n/APi65eivmf7Txf8Az9l953ezj2R1H/C7vGn/AEN3if8A8Gk//wAXR/wu7xp/0N3if/waT/8AxdcvRR/aeL/5+y+8PZx7I6j/AIXd40/6G7xP/wCDSf8A+Lo/4Xd40/6G7xP/AODSf/4uuXoo/tPF/wDP2X3h7OPZHUf8Lu8af9Dd4n/8Gk//AMXR/wALu8af9Dd4n/8ABpP/APF1y9FH9p4v/n7L7w9nHsjqP+F3eNP+hu8T/wDg0n/+Lo/4Xd40/wChu8T/APg0n/8Ai65eij+08X/z9l94ezj2R1H/AAu7xp/0N3if/wAGk/8A8XR/wu7xp/0N3if/AMGk/wD8XXL0Uf2li/8An7L7w9nHsjxeiiiuX2s+7JPaKKKKzNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKdBBJdXKwxI0kjkIEVcszH7oA65PpjPtXrHhj9gX47eN9MF7ovwU+LWsWbDK3Fj4P1C4iYeu9ImFTOpCLtJperA8lorqPiV8EfGnwYvVt/GHhDxP4TuHO1YtZ0uewdj7LKikn26e9cvjCg9B3JBx/n3yRSjUjL4Xf0AKKKKsAooooA8XooooMz2iiiig0Cvsj/glp/wR68U/wDBQ+41LxVrGrW/w9+DvhV8694s1ELHF8gDyQW+9ghkCHczsfLiBBYk7Ufw/wDYd/ZS1j9t79q3wX8L9DZobrxTfiK4uAuRY2qKZLi5PbEcKu2D1IAHWvt//gvD+3PpvgV9N/Y/+C5/sH4R/CFE0vV1tJSG1rUY+XimfILLDIW35B33HmMc7Ux5+Mr1HP6rh/ie77Lv/kV5na+K/wDgr/8As2/8ExYpfCv7Ifwd0PxTr2nBobj4heKY3lNzIu4M0Zws8kZIzkPbx8HahBBrwfxV/wAHLP7YHiLVGuLP4h6ToMLHItbDwtprxJ/s/v4ZZP8Ax6vgv/HP+f8APpSD5gvT+ZH4ZySO+PWphlmGj8a5vN6/mSfpj8Iv+Dob40W1udH+LnhH4ffGLwjfBY7+y1DSksbi5TuoZFMGPZrd69A8Vf8ABOr9m7/gsp8NdU8a/sj3UHwz+LGkwi61f4b6rItvb3mBz5A3ERAscLLETByqukLNlfyPAwTwOevHWus+Bnxz8Vfs1/FjRfHPgvWrvQfEnh+5W5s7yByCGXhkcchlYEqysCrKSpBBIqamWqD58M+SX4fcVzIy/H3gLWvhZ401Tw54k0u+0XXdEunsr6xu4jDNbToSGRlPQgjGP1PU49frB/wVr8DeG/8Agp3/AME+PCf7a3gbSLfS/F2kvH4d+Jum2hJWGWMrEsh4JLRvJFhmyTBcw7j+74/J+unB4r21O8t9n5MJaBRRRXWSeL0UUUGZ7RRRRQaH6kf8GyOm2fw28Q/tG/G25t47iX4R/D2SaASD5UaVZ7kt7Hy7Blz2DkdCa/MPxF4hvfFviG/1bUrmS81HVLiS7u7iU5e4lkcyO7erFiTn1NfqF/wbiQ/8LK+A/wC2d8LrRt+tePvhyVsol5eXbb6jatgdwGv4h9WFfli3yjPIxgHP06/1/CvLw/8AvlW/91fKxX2SxpWkXeu3n2eytbi8uCMiKCNpJMDG47VBPHTpjpzX6Lf8EFfhpfRH9qCbVvD96PL+DGsrbvd2TfJL8mAhZfv/AC8Ywfavjf8AY5/bQ+IH7CHxXl8bfDXU7XSPEU2nyaW1xcWUV4q28jIzrskVlyTEO2R2xk5/Wj/gkJ/wWg/aC/a0l+PbeOPFWmaoPAfwx1PxJo6xaJa26xX0Gzy5D5cal1GT8jZB3c5wKjNqleNJxUVbvd/5DgfizdfDzxBZQSTTaHrEMMKGR3aykCooBJLHHCgAnOAKxwcH+tfaHxr/AOC//wC0/wDtA/CfxD4J8UeNNIvPD/iqwl0zUYI/D1jBJNBKpR1DCMEZUkZUgjqCDXxfXfhpVnD9+kvT+kQfqp/wbZ3x+PPw/wD2nf2fdQY3Ok+PvAsuo20D8i2uI91m0qDs266gII6eTHjGK/Kuv1P/AODWCD/hAPjt8dPildfu9D8B/Dm4S9mPCx+bcRXQyex2afIfopr8sK48NpiqyW2n5FdAooor1CTxeiiigzPaKKKKDQ+ov+COH7bkP7A/7fvgzxtqUjQ+F74vofiHH8Nhc8NJjv5Ugjmx3EJHU12f/BdH/gnxdfsQ/tj6tq2i2gk+GPxLml8QeFdQgAa02ynzJrNXBx+5eT5Rk7omiPViB8Vdf0/Tp/8Aqr9NP+CcX/BT/wCF/wAaP2Yrf9ln9rW2kvPhyrRw+E/Fqg/avCrjKxI0gBZEjz+7m2kRgskgMP3fLxUJ0qv1mkr9JLuu/wAjQ/Mv/wDXmu8+B37Tvjv9myPxQvgjxFcaB/wmejzeH9aMUMUjX1hL/rICZFYqp9VwR2Ir7G/bS/4N3vjN8Aw3iX4XwxfHL4a3ym503VvC+26vfIbJTzLZGZpDjHzW4lQ9cqTtHwp4r8Aa74C1Q2GuaJq+i6gp2tbX9nJbzA+m11U11UcRh8RGyafl/wAOTysyMYHb04FPtreS9uY4YY3knkcIkajczk4AAUck5I4GTkgYJr2T9nb/AIJ2/HD9q/Wrey8A/C/xhrq3D7ftn9nvbWEWf+el1Nthjx7vX6R/Bf8AYn+Bv/BA7RrH4p/tIa9pPxC+N0Ma3nhTwDoswnTTp8Hy5n3AZYNgfaJFWKM58sTOFNZ4jHQp+5H3pdlu/wDIFG+5k/Gjw4P+CMn/AAQzb4c6sPsPxw/abuDNrNi3/HxpOmAKHik54VYP3RBBPm3kwGRGcfkXXrf7cH7ZvjP9vj9ovW/iT45uY5NT1UrDa2kIK22mWiHMVrAD0jjBbk8szOzEszE+SU8Dh504uVX4p6vyfYkKKKK7QPF6KKKDM9oooooNAo/znFFFAXPbP2UP+Cjnxt/Yiuf+LZ/ETXvDliz75NMLrdabK38Ra2mV4d3J+bZu5619leGf+DsP9prQtJWG60X4R61Io5ub3Q7tZH/2sQ3kSf8AjtfmTj+v69aP4t38Xr3rjrYHD1XeUVf0HzM+8fjx/wAHJH7Vnxv0uWxt/GWk+BbO4GyRPDGmR2km32nkMk8f1Rwa+HfFHirVPHHiC61bWtSv9Y1W+kM1ze3tw9xcXLngu8jksze5JNUP8/WitaOGp0VanFL5CuwAx/8AqooorfYAooooA8XooooMz2iiiig0CiiigAooooAKKKKACiiigAooooA8XooooMz/2Q=="},8625:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg"},7728:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg"},9593:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg"},2038:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAhAB8DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8G8UV2H7P/hXS/Hfx28E6Hren+LNY0bWddsbC/sPCtutxr19BLOkckNhEwKveOpZYkYbWlZM8E1+nw/4JXfsvOuX/AGc/+CtmW5B/4QDST+vkV+j4rMqWHnyyTOTlZ+SNFeufty/Crwv8E/2p/FPhjwX4d+LXhLw3pv2QWelfE7T4bDxVa+ZaQSv9rhhVY13SO7x4UZhaNjkkmvI67KdVTgqi6iOu+AXirS/A3xz8Fa1rmpeLNF0XR9esb3UNQ8L3C2+u2NtHcRvLNYSN8qXaRqzRM2FEgQk4Br9A/wBpn/gqh8NX+B+tf8Ka/aQ/4KWL8SP3B0o+NfH9r/Yg/fxCcz/Zbjz/APUGYIE48zyy3AavzOqSKTZt6KufmOD/AJ/w6jmubFZfCvNVJ6lczP1M+Bn/AASH0P8A4KW/APw/+0xq/wC0L4t1jQ9HsLmX446l4qs7i/8AEGjT2EHmsLLPnPeRi0SCJGZnIEasBktaw/l94qh0238UalHo1xfXejx3Uq2M97CsN1NAHPlvKiO6pIVwWVXYAkgMw5P1V8Ef+C2v7QX7PGm/CnTfB/i638P+G/hHazWun6FZWCW+ma2J5Gad9SgQqt27qVTdJyuwMpSR5JG+WPGXiebxp4t1TWLi3sLSbVryW9lhsbVLW1heRy7LFFGAkcYLEKigKoAAAArHB0akJtT+HoErdDNo/j/GiivW6Eg/+qP+9/Sh/wDW0UUMD//Z"},4783:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAhABwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8HSuMcfe5+tIw2nkH+X+e351Ijrj5mxuHX8cn/DFf0f8A/Bov+wz8Tv2VPh98XPF3jjQdP07w78ULbw9e+FtQs9d07VINVigGpea6mznl2hPtEIIfacsQBkMB+jZpjlhqXMtzmjG5/N7Gu87QGbd04yfQfrTa/U7/AIOmP2H/AIkeA/8Agol8RvjXq2h6fp/w08cXWk2eganJrlh5+qTQaNZQTCOzExuiI3hkDN5QAwD91lJ/LGtcFiFiaEZvcl6BX6+/8EVf2m/20P8AglPqmoeHdT/Zj/aG8c/CfVhLcyeH/wDhCdVjm0272/LPaO0BEe9lVZEOVZcEDcMn8hoxnHrj+v8An/63Wvdh/wAFVP2nl+7+0d8fF/7qBq3/AMkVjmOFq11yRSa8/wDgDjKzPWv+Cq17+1v+138Ude+NXx0+EvxY8K6JZmOCE6p4S1PT9E8M2ryiKG2jkmiCRqzyKNzMDJI5Odzha+K69g+Jv7fHx1+Nngq98M+NPjX8WfF3hvUvLN3pOteMNQv7G6MbiVPMhlmZH2yIrrkNtZVIwQK8frXL6dSlT5ZJL0FLUavRvoP50P0ooruETr/WP+VRUUVUQP/Z"},8121:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg"},6072:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAC4DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6ByccknJAAyTjr/AIUV2n7Pnwcf48/FvSPC6+I/CPhGPUpwLjWPEusQaXpmnRggtJLNMyq21cny1y7HhVY8V+nVKihByl0MY6h8BP2d/HH7UXxAj8K/D3wvq/izxBJBLdCzsIC7JFEoLyOThUQblXcxALOijLMoPJ6tpV1oGpT2d/b3FjeWsnlTwTxtHJCwJDBlIyCMHIIzX9YX/BOj/gmX8O/+CbHwj/4R/wAI2/8AaGualHG2teIbyNBfaxIu4gEgfJCpaQxxAkRhjy7Fnb5b/wCC8/8AwR68A/tLfDjVPi9puv8AhX4a/EDQY4zfaprV9Hpuj6/GzRxRQXU0jrHDMz+WkUpI3MyxNwVeP52lxAnV5JLTuU4dj+dnGOvFFTalp76TqM9rK8EklvI0TNDKksbFSQdroSrKccMpII5BI5qGvpFZq6Mwo3kscE7vujHYbcL04BBxx1/iPBzRSyjyz/ezuzn2GR+v5VNSClHkfUqLsfvv/wAHCv8AwUr8NSfsX+Ff+FE/HzRW8Xf8Jpam7/4QPxvGdQ+w/YL/AH7xZT+Z5Hm+Rkn5N/lZ+bZWH/wUA/bi+Hfxg/4N2rXw1J8X/BviX4nX/grwiNR0x/FNte69c3qXOlveebD5puGmVkleUkF1KuW5Vq/CCWdvK3H5id5+Yk/dYD9f8OmBh2nv9shG4bVaURkAnBGQvQ+x6dOBxivAp5HGMU77O4/aDiTn0z1Gf0pKB0or31okiD//2Q=="},8e3:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAkAJgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6x/H2q3GieEb27tZBFcQiMo+0NjMiKeCCOhPatiuf8AikceAtQ4/wCeX/o1K/TpXtoc5523xZ8RKP8Aj+X/AMB4v/iaT/hbXiDbn7cn/gNF/wDE10uqaFZatosdxqMdukcgCLrWloJIVbAwk8QwVPYkYPGdr1it8Ip7T/SLvUNNt9HzlNRWcSRXA9I1X52b/ZIBXjdtrengcRNc0Ff+vw9Xp5nRiMO6UlG97/1/XQqr8W/EJH/H8o/7dov/AImt/wCGvj7VvEXimO1vLpZoGjdiohjXkDjkKDUOt6PDpHhCdrSzt7G1mUCO81ID7ZqQ45ij52IeuRnHTeelZvwbH/Fbx+0Mh/SueUJwnyyFWw7pWu73R62G4pwNfQ3wI/4J4XvxQ+Aun/E7xh8Svh38HvBWva23h/QL3xZPcmTX7lOJjDHbxSMsMRKq80m1FO7JwCax/Hn/AATj+NXgn9pTxh8J7b4feJvFXjPwMynVLbw3p02qrHDIqvDcAxIT5UqOjKWCnDYODkVh9co87puWq3/ry6mGtro8RJpN1emeA/2LPjF8UtR1e08M/Cn4ja/d+H786VqkGn+Hrq4l068Vd5t5lVCYpAoLbGAOMdBk13fhP/gl58YPE/7MfxO+KD+E9d02x+FOoRafq2kXekXceoTNk/amRTHtVLRBvnZyPLXk4qpYqjF6yX39w9T543UbsivU9W/YV+N2gaxomn33wf8AidZ6h4kna10m3m8NXaS6pMsPnFIFKZkYRZkwucLyeAa7T4A/8E4PGHxQ+K3xE8F+NI/EHwo8QfD/AOHmqfEF7PXPDkpub6KyETLB5UkkDRrN5hxN84UoRsbnafWqSjdyWn6bjSPnjdRmvV/2QP2P/EX7ZHizXLPSdR0Hw1ofg/RpvEXiXxHrtybfTPD+nxAbppWVWZiSQFRFLMc44Umuo+Of/BOrxb8L9F+GuteEdX0X4yeGfi089r4Y1TwZBd3Bvb2BsTWLW0sSXEdwvXY0YJAJHKsoJYqlGfs5PUVr3seA5pN1eo3P7DvxosviQ3g2X4S/EmPxZHpba0dGbw3di/8AsKyCNrrydm/yQ5ClwCASASCQK9G/Z7/4JJfHH49/GPV/A83gXxV4L1nRvDs3iOYeINBvbcGJVfyYgoiLCS4eOSOLIwzxuAcjFS8VSSu5L7ws0fNG7FG6vSfDP7GXxh8Z6J4i1LSfhR8RtSsfCN3c6frlxa+HbqaPR7q2z9pguGVCI5IcHzFbBUqQdp4NG9/Za+Jum/B+L4hXPw78bW/gGaCK7TxJJotwmkvDK/lxSC4K+WVZ/lB3YJwO9X9ZpXtzL7x2Zwuc0UDpRW4grn/ikceAtQ/7ZYz/ANdUroK574rcfD7Uj6CP/wBGpUy2DYzrSX+x7O3vGkt9JkmURpqWnR+dp13kZ8q4ixwf7wx0HKHrU50KTSlbUDouh6TI3J1iS58/TeM/PbRchpD3AL4I4RO3mnhrxjfeFrpntZdiyDbLGyh4pl/uuh+Vh9RW9/wnuk2ca3VnoMUWpnBBmmM1pA3do4mHU8cOWAx0Nezl2OhCk4Savb+un5WO6tioVXGVrW/rpb9DU8WKtz4YuryNDdLcctqurP8A6ReHIBECZOB7/Mf9pelYvwcBHjiPt+5kx7cVz+teIrvxBetcXk0lxM38TnOAOgHoB2A4FdB8GH3eOI/+uMn8q8WpU56nMY4rERqyVuit/X9P1P1C0G9+Hn7eP/BOv4L/AA51H4veAvg/40+Buq6va3cXjGae2stX03Up47gXVvJFHIHmjKbTESmcHJUFGPaeH/GfwT174AfGr4E/B/4+Xfw3t5PH+j+I9E8afEC/lsH8WadaWogmie6tbdGUx3RNxBE0SllSM8Hey/nNtyRnnb0Pp1/xP50gXBH+z0HoPSuCpl7lKUlLRu9vO9/zOe+iXbRemv8Amfqd+3r/AMFDPh38Vfgj8eovAPxDWPVNf+Ing9Ybi3uZNPvvF9vp2nQwXep+WCHaEzxLyxOfKjYgHBrU/bz/AGp/hX+0PYftveH/AAv8WvBNrceNrzwl4k8N3FzfyxWfiNdNtUN7bWsiIwe5dk8sRkDe7AEhcsPyewfX8vy+v/6z6mjGB8vy/T/P+eR0rnWSwVkpP+rfqhzlzWP1v+KH/BQnwL44/wCChHxa0mH41R6X4T8e/BWPwX4O8VHVLmfQ/CesyWEG+TKFvsoZ0kR5YlDBn5+8ao+F/wBr34V/DPwv4b+HeqfFbwn4w8ReAv2bfGfhHUfFlpeTTadqWpajcW0lhpFpczIj3BijidVO0KAcKF+ZF/J4Lg8cf5/z/wDXpCu7/d9P8/h+Qqo5TFPfp/n/AJjjLlVl5H1h/wAEwPjB4I0n4d/Hz4Q+O/FNn4Btfjh4Pt9K0vxPfo7afpWo2U7XECXRQMyQSlyGkAITYBjnNe7fsGeIv2ef+Cb/AO0z8ObjUPjDpvjjxl4g8P69p3iHXdKae88E+C7i7hEdi8LpFBePI2JI5pY3Uokv/LMEsPzbx/n1puzIwcFT1GOD+FdFbAqpJvmaT3S9LBF2XL53P1u8I/t46H8NLi88M6x8UP2d7NfC3wQ8c6X4Zufhlca2INP1G/ls3tbNNQ1G4kkmmkaEyRRxFGibcMkFDWX+zJ+2j8MbXRf2TdN134oaFpmqWPwf8b+DfEN9f6hI66Fe3jRf2fHfOoZo1IWTYWHy8Beor8pgMDH5+/8An8qXtjqPQmuV5LBw5W+z/B/5hza3/rp/kfrh+y1+234N+Gn7MXwK03wz8UP2cfDnjT4A3euaZr1341fxBM1zK87n+1NHj0+eFNRiu4z/AMtY97hwDg7kPyn/AMFE/wBrS1+LP7Jn7NHhXw140Wa00jwhd/8ACT+GtG1CWLT9Ov5L9pUjmtd5UMqbdgkBYIBzXxyVyu3Jx9f8+/SjbxW1PKacavtW7u9/z/zKjUsreX+Q5aKKK9QzCq2q6Xb61p8trdR+dby4DoWK7sEEcgg9QDRRQBjH4VeH9v8AyDV/7/y//FUL8LPD7H/kGr/3/l/+KooqYxQC/wDCqfDx/wCYav8A3/l/+KqzpXgbSfDt6tzZ2awzfc3ebI3B4PBYiiiqsrga69KWiigAooooAKKKKACiiigAooooAKKKKACiiigD/9k="},9026:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAC4DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8mutaPhHwhqnxA8V6boOh6featrWtXMdlYWVrEZZ7uaRgqRoo5LMTgYrNPzH+dffX/BBrws/gTxX8cPjvJo8eoSfBL4f3t9oU11aNJZw65cDZbMzD5MqiS5UkHbJuGNpI/RsZXdGk5/d6mEdWdN4J/wCCEHhP4cOul/Hb45Q+E/iDNp8WqT+B/BPhu48VatpFvIAc3htw2xvmUYWMpw215AwI4H9qD/gi3feD/hbrnxE+CHxE0744eDfCwDeIbGLTZdN8S+HMjfm5sHy5QIdxb5G+8dmFJr6C/wCCin/BQPUP2Zfg18KF/Zt/tT/hGdN8Wy6z4m+LkdoUtPid4qhST7YGkOGuonlluJHJ/dSfKsGYoBXsVr/wWF034i/ED9nfx34s+Dfij4Y/FPx5eWWmrrUFlbT6L8QPD13cRWt9BK7OJTDnZPAHR2R4U2sI5XZvn44rGpRrN3Te3oacq2Pw5V93TmnV7p/wU1/Zw/4ZM/b6+K3gODTrjS9J0vxBcXGjQyxlB/Z07edbbM/eURuqhhwTGe+RXhdfS0aiqU1UXUyGn+npmvvP/gn3/wAFH/AP7Pv/AAS2/aM+CfimPVrXxL8Qlmu/D9xbWpuLa7eW0igMMjBsoytEG3Hgq/XK8/BpGfx4oB3En+9yffnNTiMNGtHll0af3BHQ7H4c+GPiD8e7jRvh74Xs/F3jKaOSe80zw5psc14Vk8vdPJFbLn5iiEsQM7UPYGvpj9mn9gT9qEftIfCFvEnwh+Nn9h+EvEWnCBtQ0G+Nro9qt4kkgQuu2KMEsxxgcZr5Z+E3xe8U/AXx5a+KPBev6n4X8RWCSJb6jp0vk3EKyI0cgVh0DIzKfZiO9eut/wAFXP2mHRlPx0+JW1sg/wDE3YZ/SubEU6z92la1upSaue4f8HJXxx0740f8FVfFdrptvLCvgXS7HwxdSSY/0i5iElw7LtJ+UC5VRnByjeuK+D+an1nWLzxLrN5qWpXl1qGo6hPJdXV1czNNPczSOXkkd2JZmZmZmYkkkknJqGunC0VRpRprogk7s//Z"},2764:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAeADEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6M0U6KNppFRFaR2O0KoyXPQAD19q/UDnCKNp5VjRS0kjbVUcsx9AP8APUVs/EP4beIPhJ4rn0LxRouqeHtatVR5bHUbZ7e4jV0EiMUcA4ZGDA4wQc1+0/7CH7JNl+yN+x/8EbXUPgD4N8UftRfEzWL258Lf8JLCI49Lt4c3H2++kAZ44beBozsC+aXkjUBWII+gfiN8Obr47/tF6P8ADP8Aas+C/wAGNc+IXjjwxqI8C+NfDcdxNY3U1pEZZtPkS6UzwyRCTzlZmaNl3Yw25R4dTOVGpZR0733SNOTQ/m89P9rp7/Siuq+N3wS8Vfs6/FTWvBfjTRbzw/4k0G5a3vbG4TDIRghlIyHUqVYOpKsrKQSCCeVr26clKN0Z+QUUUUwCnRStDIrqzI8ZyrKxBQjkYOeMeox+nLaKAP3K/YS/azsP20v2VvgNe61+0D4T8L/tS/DXXb208Nt4gZZ21yCbNv8AYL2LcrSC6hESecp87cqsN0jHd718S/ib/wAKL/aS0z4k/tUfGD4KaH8QvAvhvUm+Hvg7w7JOlraNex+VPfzNdHz5ZJTCYUG1ECiTG5i2P5u4pzayh0Zo2U8MnBHp39efb9a2PiB8RfEHxY8W33iTxVrWreI9ev8Aa15qWpXT3V3cbFEa7pZMs21URRk8KqgYwMeHUyZTqcyl7rv8r9PzLVQvfGL4xeJ/2gfifrXjTxnrV94h8UeI7g3eo6hdvuknkPAwBhVVVAREUKiIqqoVVAHM0Hqf196K9qEVGKS2RAUUUVYH/9k="},6424:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAdADEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6WKCS7uI4YY5JppXWNI0UuzsxCqoUckkkADqSQByaSvtj/ggH4K0nVP27dS8b61aw6ha/BfwNrXxCis5AAt1PaLDDEA38LK10JAexjHWv0nFVvZU3U7GMdzcsf+CRnw5/ZS8E6Pr37Xnxq/4VTqWv2ou7LwJ4bsBq3iZYT0kuGxIkJ4+6InHON4Ksov+Hf+CZf7L/7Y8dxpP7Nf7TF9P8QsldN8KfEHSl09tblB/wCPeG4VIgkmBx+7lLEKCFBLro/8EWvjVZ/tJ/8ABSH4j+PPiLqWgap8ZvFXhzUdU8B3fiwhtLTX2ljeJdrcI0cfywIMCONHVQCEA7D/AILzz65afs5/Aq4+NF/4LX9rW1uLl9fl8LOkdxbaWCXtTcNFwrodjIQQAxkKZGTXgSrYhVlScnd22tbvtbbu7mlon5t/Fv4TeJPgP8Tdc8F+MNHvNB8UeGbr7HqWnXK7ZbaTarDPqrI6OrD5WV1YEqwJ53sv1H86/QT/AIKw+IP+GrP2AP2Uf2j9YggXx34u07U/B3iK8Rfm1aTSrqa2juJD1aRmhmbPbzSOgXH59joPqP517eDrurS5nvez9UZ2syGiiirNixX1F/wR3/bC0X9ir9uDSde8WD/ihvFmm3XhDxQ2cCHT7zZulPB+WOWOF2A/hQgYr5dobr+NVWoqrB05dTnW5+pHx7/4I+fs7f8ABOnwzJ46+NnjD4pfEnwr4pv5rnwlYfDjR1kh/soyeZby3WoSFbfzGhaPpJGpLEp5gG5cP4F/8E+v2Uf+CrR1XQ/2bb742/Dbx9a27XVuPGmlpqmg3BXcWSW6tXlEWQMKWlDccI/Kj5i/Y+/4K2/H79h7w5/Y3gXx1O/hdi+3w/rcC6ppkJ6fuo5PmhHJJWJkUnkgnmuw/aD/AOC8P7Tf7RXgu88J3nji08J6Dcp9murfwnpqaO13H/caZCZlU7cERyKGUlTlSQfn5YXEqdubXo79PS36mnMjpv8Ags78WvB/g62+Ev7NHw71f+3PDP7POjSafqmqwyiS21TW7nEt20TLwwViwYjgPI6YGw18M/wr9RSRxhYto4UcADtR2/EV7uFw6pU+Rf8AD3J6kNFFFKxsf//Z"},1977:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg"},8082:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaABsDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Xv2av2dtW/aV+IK6Lpskdnb2sX2m/vZFLJaQggbscbmOcKuRk+2TX6O/Az/gitovxJ8HXlx4d+H/AIi8aW+lx/6bqRnYZIyGI2lVHKtwoONp6np5/wD8EKvCPgHxN4f8ZL468RX3hnT3kkLXllbC4leZIVNvER2Vi0pz6hRkZ3D9Bf2+fiL4s8C/tJTaPb3F94J0Xw/pemwaFZ6PeSWVstqtpEyujRlfNxI0qhznG3A75+F8QOKce8fUiqkoUabUeWDSk3bd+X5n794f8O4F4WlSp0YTxFaMpudVNwik7WivtPXWz06n5kf8FJf+CP0n7JzTX3hfWNI1lLXTYdVvbHT9R/tBIYJFzlJdqncoBZ0YEgHcpYV8JlcHtX9Cv7Y8uq+Mvhd8H/EHjLRdLsPEviPw9OLy5jkxd63aJKVhurq38lFjcoeCHfer5wOFH8/Xi+zt7LxbqkNrta1hvJkhJYnMYchefpivtvDnibEYuVfB4m8vZ8ri3vytJ2fmfE8d8O0MJh8NmFBKMqnPGSVuXmhJpuNujPVv2KP2qF/Zn8dXR1KKe68N62iw38MXzPEyn5JlHdlBYEd1c98V+s3wO/4Ko6fH4HhaPWPhz46t7W0hh0y78TRR3V5okUYYIkfnEPHtycK68EDkgDH4Xk/N/n1FPcfMv0H867uLOAsNjsT9fo1HSm97JNPTqmcfDPH1fBYJ5diaMa1KL91SunG71s1rby2P1L/4Kvf8FavCHxM1y7k8AtqE3iG80iDS5ZptZl1aKyZQRJOs8hPzFWO2NCVVssecg/lqdzndgNu5ycU1Tlo/93P86RRlRX0nDPDeGyuk3Sbcp2cpPdvb5LyPm8+4gxGZzhSqe7TpLlhFXsl8933Z/9k="},5401:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAkAFUDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8PfhV8L9S+MHjKHQ9La1jupkeQyXDlY4kUZZmIBP5AnmvVT/wT18YL/zGfCf/AH/uf/jFZ37CI/4v1H/2D7j+S19nN+Ff2f4c+HuU5zk8sdjVJz52tJWVkl5eYsHh41ZWkfIB/wCCfPi8f8xrwr/3/uf/AIzTW/4J/eLkP/IZ8K/9/wC5/wDjFfasnw38Qf8ACO/2r/Y2oCw8zZ5nlHd/x6/bN+z7/l/Zf33mY2eX827HNUfCfgvWviH4kt9H8PaPq3iDV7wN9nsdMspby6n2qXbZFErO21VZjgHAUk4Ar0cZ4d8NwjKdKTaju+dNL1fQ+xwXDuDqK9S/3nxsf2BPFw/5jHhb/v8A3H/xmmH9gnxYg51jwz/3+uP/AIzX3AnwF8eTWE10ngTxs1rBqo0GWZdAu2jj1IyLELFm8vAujK6RiE/vC7qu3JApuifs8fEPxck7aT8PvHmqrbI7TNZ+Hby4WEJLJBIWKRkKFmhljYnG14pFOGRgPjcZwzkVJNwqf+To+uwPBWR1P4kn/wCBI+H2/YM8Vj/mNeGvwluP/jNNH7Cfihf+Yx4b/wC/tx/8Zr7Wg+Bfjq80K+1KHwP40m03TbiO0vLxNBu2t7SaQRmOKWQR7UkfzodqsQzedHgHeuXeH/2c/iL4ySaTRvh7491iO3VzK1j4cvLlYgkjxSFikZChZIpI2z9143U4KsB8ljcrwFJNwnt/eR9hg/DPheavVm/P94l8j4nb9hfxQG/5C3hv8JZ//jVNb9h7xQo+XVfDznHCrLN83tzH3r7D8XfCjxX4C0XS9V17wr4n0HS9djE2mXmpaTcWdvqUZVXDwSSIqyqVZWBQkFWB6EVzinDL0618pjOWCvSZ9zl3gfwniqftIc8lrqp3Wnov+GPz91DT302+mt5VVZbeRo3Gc4YHBH6UVpeORjxzrX/X9N/6MaiphK8U2fxhjIxpV5047Jtfcz079hD/AJLzH/2D7n+S19l3KebEy7tu5SMjqK+JP2M/FWm+EPjhb3OqX1rp9rNaTwCa4kEcasyjAZjwucYycCvrx/jB4PP/ADN/hP8ADWLb/wCLr+pvCHMsHR4dlSr1Yxl7SWjkk9o9Gzsy+SU9WfVr/tF+GU8Yf8Jwvie82/bf+EgXwd/ZDm7/ALV+wGz+yG64t/7LwAhO7zPs58v7OW5rxf4LfEu0+Ft3r8GpaTca5ovijw/deHNStre+SxujbzGNt8M7wzpHIskKHLQurJvUj5+PNH+L/hAj/kbvCn/g5tv/AIuo3+LvhEn/AJG3wt/4N7b/AOLoqZXkmHo1KEa6lGaS1nHRRvZJxs9L76vu2foGW1MPJcs5rXzPrjwp/wAFGLbwd4y0nxDD4Dv7rVtCxp9mb3xfNew/2T/wkcOvm3m8+3kmmvDNEYfthmC7WVjbs0aYyvjF/wAFG9U+L3wivvDt54N8OLq2qWFvZ3+q3Vva6lFfSRXt7dPdtaXNq8a3U32v55kIfzUeZSrSlV+Vn+LPhLH/ACNnhf8A8G9v/wDF1FL8V/Cf/Q1eGOn/AEFrf/4uvzvHcP8AD8Z+0jytp31m359ZP7tj7TLcHk7mpzlG6d9Zf8E+qta/b+sdctZLi6+Hyza9Y+euiXp8QEQaek32Fn82EW2+Zt9mTlJoVZZQrrJ5asdnQf8Agp1ZeCbi1h0f4YwPpdnq0OtW0Wr69HqN1aXK6rfalJLDN9hRElWS9X7PIYWMLW6O/n5K18bt8V/CpX/kavDP/g1t/wD4uo3+KfhXP/I0eGun/QVt/wD4uvi8xyrK0mo2/wDAn/mfdYLKeG6seWrKLXb2jt93N/XzPZf2kfj5pfx+k8N3Vv4Wfw/qmh6RY6Rc3AuLCZdQS1sLWySRnh0+3uXYraK3+lXFzsDlIzGvB8tH31rIb4oeFz/zM/hv/wAGkH/xdRH4oeF4hubxL4d2rySNShJx9A2fyr5DGU6VOPJS29bn65w/jsly/Cxw1CvTjCKdlzp2vr1Z8WeOf+R41r/r+m/9GNRUPiy8TUfFOpXELb47i6lkRv7wLkg/lRSp35V6L8j/ADrzD3sVUlHbmf5mbRiiitjEMUbRRRQAm0elBHHSiigBpPHQUqrkUUUuVWACvBoQcdKKKUQHUUUVQrs//9k="},5987:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaABoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Wf2YfgZ/w0p8bdE8E/8ACZeAvh9/bXnn+3vGmrf2Vodh5MEk/wDpFwVYJv8AK8tMqd0kiL3yP0U+Hv8Awb8/AjUvAthdeLv+CiH7Meh+JCrm8sdJ1XTtVsYsOdgS6m1G3eQFdpJa3TDOVwyqrH4r/wCCVo/42e/s4r/1VHwyee+NWtT+H+RX9rCR/L9env8A4dentX1eeY6tSrJRfQzjTXU/in/bm/YS/wCGJbnw7Gvxk+BXxcXxC12qn4c+K/7cbSvs/k/8fg8tPJ8zzv3Yy2fJlH8OT4DX63f8HmQ/42h+Bf8Asl2n9u39ravj/P8Ak/kjXt5XWnVw6nU3ZjPR2PUP2J/i/pf7PX7Znwj+IGtLcyaP4F8Z6P4hv0t1DTPb2l7DPIEBIDOUjbAJGTgZGc1/UYn/AAc8/sQ+V83xpaM8na3g/XsjA5GRZEE9emR/X+SfH3v92hVGeg/KuLNMBTxElUejNIyaPv8A/wCDkn/goF8Nf+CjH7fGi+LvhXqV9rXhnw74OtPDjX9xYy2a3U8d5fXDNHHKqyBNt0gyyqSQwxgAn8/Kcqjb0H5U2u/BU40qShEzqXbuf//Z"},2383:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAIUDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Gs7aBX1D+yt8Jvh7ffsUfE/x/wCKtP8ACd5rWgeJdK0jS38Qy62Lcxz6fqc7xRJpisfOaS1hIe42xDaQWGTXqPxJ/wCCRfgv4dyaldf8LI8calpfg621N/E8Nr4Mt21Lz7W20GdE0+L7dtuI2OvR73leEolrI+1shR+iyzKjCbpyvoc/I7XR8G5+v5UZzX6S+KP+CKngnQb/AML6HqXxB8RaXeap4yHw9tL6y8KC4l1TUrnXPENha3F3FLfqtvDHHouXEO5hu2hHYFz4X+0P/wAE6vC/7On7Pnh/xVqHxA1LWPEWraLp+oz6Lpmj284t5NR0qPU7Rg/2vzFtY0dop5ZY43D7GjjlQsyqGbUJNJPX0J5W1c+XbLS7c6at1dXDwxyytFGscXmEsqqzZ5GB8619kfsHaD+zr4l/ZY1Cz+Ll94b0/VrrXZ45riSZLbV4LfztGMBglG+ZN0Y1NAUgkhG52mK7Iw3x1fceE7H7v/H7c8jv+7t69n/Zg/YW1j9oH4c6v4tvNd0fw34esdP1+awE8wfUddu9K0p9Rlt7W2yDIAvkLI+4BBNkByNtbZhFOl78uXbVBD4j27TvgR+yGPAHgXUNW8YPb6p4qtIYdZtLDxNJKfDhnNgXuyjWhYyWxnv0+zuRvWyjyx3ebLl/G34d/sv6D8F/Eek+H7/TpPEUc+q3ugata+KZNQuZYIILf7AJ0NnGgN4N7NBu3QSF+YyfKj5vxN/wRq+OHhfV9PsLjTfDs1xeaoujzmLWEZdOvFuBbXMU7FQE+ySNF9okGY41mRtxUlh5F+yZ+yF48/bi+Ly+BPhpYabrniqa1lubawn1W3sXvkj/ANYITO6CRguW2KS21WbGFOPPpxpSXN7XYq7XQ86httMaJWlvLqOTbllW1DBT3wd/SotWsG0jUZrVmVmhcqWX7rDjBH1681o/EvwBqHwq+IGteGdWk06TU9BupLG7awvYr6282M7XCTRM0cgDAjcjEHB5NV/GRz4ovP8Af/oK9yMlKPNHYzM9Rvb5eaCpXj+tfZH/AAQZ+Gfwp+KP/BTL4c6f8XNc8M2Gg/bM22leJNFj1HR/FNw6NGmnzGRvLid2cNGZEdGdAvDFA3Tft7/s7fCfxF/wW01vwR8Kbeb4n+EfEXih4U8MfDrToNIit7hy4XSbGX5oNiMqCS4WNY4wZCAwTNefPMeTEOi46JXuVy6XPhDvS55r2r/goZ8A9J/Zk/a58WeCtD03xBpGm6P9lVbbWI5xLHM1rE1wIZJ4YJZ7UXBmEFw8MZmhEcm0bsV4pjLKPf8AOu2jWVWCqR2YnoAO4cUua9w/Z5+Gng3xh8GvGOoatbapdX2lW/mXEyRopskCvIptvn+Z/wB3kl9oIO3pknkfg78MdN8f2esyTrqNxFZyrEkkOIvssTRXEhuZVG4BQYY1Izt/eEbs7aftE2I89BzRTV6fzorQDrPh18ePHPwfsNSs/CXjTxb4VtdZULqEOjaxcWEd+ArKBKsTqJAFdwNwOA7DoTXSfBv9sv4j/A34n2vjDR/E19ea5YtNJDLqztqKpJNFHDJKFlJxI0UUUZcYYpGq5KgCvMaKw+rUm23FahdneePP2p/iR8S/HV14k1jxv4muNYutYfxAZotQkt0gv2nmuDcQxxlUhcS3Nw6mMLtM0hGNxznt8fvHj+ELPw63jjxg3h/T7SaxtdLbWrk2VtbTY82FId+xY5Nq7kACtgZBxXJ0jcCnHD0ltFfcPmZo3xz4Rsf+v25/9F29ejfCT9tbx78EvhLqvgvQ7rQ/7F1L+0QjX2iWl7d6ab+zFletaXEsbS2zT26rG5iYEhFPBGa8zs/EFxpVu0Mf2d4t5bZNbxzKDwMgOpwSMZx1wPSpR4suh/yx0v0/5Btv/wDEVVSnGatNXQtnc968Z/8ABVj43eOvFmsa9feKLBda8Q+HNT8K6te2+jWkM2pWeohBetIVj/10uxT5ow6kEqVJJPz7o+s3eg38N5Y3VxY3lqQ0U9vI0csLeqspyp9we5qz/wAJddf88dK/8Flv/wDEUf8ACXXX/PHSv/BZb/8AxFZ08LTh8CSHdvczW+5gdAMcCtLxgMeJ7z/rp/QUDxXdE/6nS+oH/INt/wD4iqd5cyXt3JNMzSSzHzHY9WY4JP61vbSwjtfgn+0BqXwJfVDp/h/wBr/9rLEsg8T+FbHXRB5e8jyftUb+UTvO4pjdhc52jC/GL9ofV/jPqumXlzovgnw1caTHIkJ8KeGbLw+sm8jJkFpHH5jDGAWyQCQOCa4WjFYfVKXP7S2vcd3sS3uoXGpztLdXE1zMwALyyF2IHTk5PFQl9uf8/wCf/r0tFbKKWi2EdBpPxOvtG0yO0j0/w7NHGMb59It5ZJO/zMy5b8c1i3+pS6lqFxcMscLXTs7rAgijG45Kqi4Cr6KBgdBUNGKOVAAGKKKKdgP/2Q=="},4601:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAIkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8G88UYwM19kf8E+v2WvA/xS+F/hHVPEfgPVPiJefED4pW3w7u1s9RubRvCNlLawyC/TyTgzyNPK0ZnDQgafMNrZYr0el/8Ei/COr6JpV8vxK8YRWtpBod54juZfBYktY7fVvD1/rVvJYSx3TefHEunyQzzzrBDEJllZxGjkfossypQm4Sv2OXlZ8JN1/Wtq90ez0PxElnNcNLLbXYgul8rbGNrYfDZJI4IzgZ696779sT9nrTf2Y/irqHhC1vPFN5f6PeXEF0+r6PBYRtGCr2zRNDczrIWhdWk2tsViNjyqQ58/8AH4z8Qtc2/wDQRuAP+/rCu2nWjUjzJ6EuLR+h3x2+G/7HfjL4o6eun6t4Rsmm1Ke1WLS9aGlWH2FTrU9vJKYUmiDSCLSYAzSo4SUmYRzOTFxHiL4Afsdwx+LLLQ/G1xqWp6BbkaLJfeKzZWvicySjzZZJvsDC2a1tlkdEVGM8u1cElYm808ff8El/id8PvD+tX1xrXw1vJvD8mqw3lhZeKYZLxbjS1gfUoQpCr5lrHcRNJlgoDnBJVgHXX/BI74sWN7er9s8CSaZYaEPET6yuvodMa2/tC507cJiuAv2q0mjMzgQY8tvN2Sxs/gxjRitKzNk2+hgf8FANG+CsPxN02++EV1Db6TftfxanZ2d095b27w3TxwXEIkSNo0nhCSCIltmThscDwg2ul/8AP9efUWg/+Lr6e1j/AIJCfEqdb6bwzqPhjxZY2Xh3StcFxa3Tx/bZr3w+dfextwynzJobFZJGJKqV8oghpkQ+LfFz9mvWPgz8fpPhvqms+ELjXrW9i066ubTWYm0yyuHYKY5rt9sUflscSMzBI8HLAA49TCYqly8kZX6mctXc4s2ulsP+P68/8Ax/8XTNV06Gxgt5IZmmiulLIzJsYYYqQRk9x6mvTv2xP2IPiN+wX8Q7Hwn8UNN0vQ/EmoWS6imn22r2uoTQwMxVHlFvI4i37SVDkFlG4DBBPm2q86BpLf7Ev/o0/wCNdlOpGpHng7okzhywA70ZyKlsIIbm/hjuZmtbeRgssyxeaYl7ttyM49M17X+1toHhLSNE8KtoNxoa3X2EGSLTLZAL5SFAnkZOBkqQAQSST0GTRKdnYDw3+nWnZrv/AIpfDHT/AAX4I0e+tY75Zrto1M00gaK/V7WGZpIgAAFWSQx8FugyQcivPwMVSlcBaM8V6N+yv4U0Hxv8XrDTdchurpZtz21skYME7ojSHzm3BggC9FB3E4JAqbxL8ONAf9pa48L6f/aUOlxajLayxyqqyRyRlg0UTAtuUsu1WIDYYZXPWfaK4Hmec0Vv/E/wzb+EvGMlnaw3NrGba3na3uDmW2eSFJHiY4ByrMV5APHIzWBVxd0BveC/iv4q+Gtlq1t4a8TeIfDtvr1sbLU4tL1Kazj1KA5zFOI2USpyflfI5PFdZ4t/bG+KnjK98JTXXj7xVb/8IDY2mneHEsdSls4tDjtbSKzia2SJlWGUwwoHkQB5DlmLMxJ81oxWUsPSlLmlFXA1/GvxK8SfEORX8QeINc15opLi4RtRv5bspJPIZJ3BkZsNJIS7kcsxJOTzSfEEbfiBrn8LLqVxx/21asduB/n0Nak3i68d9zrYSsQMvLYQSO3HdmQk/UkmrjTjFWSA9if/AIKR/F6fX9Q1T/hINNW/1TVNf1meUaJZ83WuJbpqMgHl4G9bWHauMRlTtCljXW6p/wAFivjlrHxWtfG02qeD/wDhJrCGaOyvR4R0zzLF5ru5vJZ4T5OUlee8uXZlI3eaVYMoVR83DxbdD/ljpf8A4LLb/wCIo/4S66/54aV/4LLb/wCIrmeBoPeCHzNHt1h/wU3+Llh4FvvDS6toUmj6ho+naNLBJoFm37uw046ZbTgmPi4WyKwmb77iKItlo0ZfG/ib8R9X+MHxE17xTr08N1rfiS+m1G/mjgSFJZ5XLyMEQBVBYnhQAM8Cqv8Awl11/wA8NK/8Flt/8RR/wl11/wA8dK/8Flv/APEVpTwtKHwRsIp6jqtxq1z511cT3U2xIvMmkMj7ERURctk7VRVUDoAoA4q5qvGgaSP9iX/0aaP+ErumGfJ0v/wW2/8A8RVfVNXm1UxtN5WI9yIscSxKgznhVAHUk1skkrIA0vUn0fUobqOK2mkhbcqXEKzRMf8AaRgVYfUGtTW/iJda9pclpJp/h63jkIJe10i3t5Rg54dFDD8DyMisOjFDimAEsyqCzYXoM9KKKKdgNXwx4yuPCS3At7XSLr7SVLG9sIropt3fdMinbncc4xnjOcCovEnii48VXUU01vptq8Q2/wChWcdqG75IQDJ9zzWfRilypgDMXbcx3H1PU0UUVWwH/9k="},3377:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAkAEEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8J7HSPtVsZ5Li3s4d/lq82/52wCQAqsTgEEnGBkc8jMn9jW3/AEGNN/74uP8A41Rc/wDIqWP/AF+XP/oFvUngnwTrXxL8Yab4e8N6RqniDX9YnW1sNM021e6vL6ZjhY4oowXdieiqCTX6s5W1Zxkf9jW3/QY03/vi4/8AjVH9jW3/AEGNN/74uP8A41XSfGb9nzxf+z94r0/RPFekx2OoatZR6hZLbX1vqEV5BI7xq8ctvJJG/wC8ikjIDEq8bqQGUgc2/hXVI7zUrdtN1BbjRVd9QiNs++wCOI3MwxmMK7KhLYwzAHkgUlUi1dMA/sa2/wCgxpv/AHxcf/GqP7Gtv+gxpv8A3xcf/GqtS/DfxFBbXU0nh/XEhsQzXMjWEoW3CojsXO3C4SSNjnGA6noRmeL4R+LJ7Ca6Twv4je1tryLT5pl0ycxxXMuDFAzbcCV9y7UPzNkYBzT513Azv7Gtv+gxpv8A3xcf/Gqh1HSjY28cyz291bzMyLJEWxuUKWUhgrDAZTnGDngnBw7UdAv9ItoZruxvLWG4aRInmgaNZWjba4UkYJVuGA6Hg4qS6/5FKy/6/Ln/ANF29O99UGxV8laKdRTAsXP/ACKlj/1+XP8A6Bb1+h//AATL/ap8I/sq/saw6Xrfxq0/wbqHxO8WNbz6ToFmYdT06xt/KuVuNXu/IvIJrGa5so7Nra5064lig1GaaEzQSahp91+e1tp9xrPhq3is4Zbqa3upnkjiUu6q6RBW2jnBKMM9ARzjIzF/wh+r/wDQJ1P/AMBZP8K5sTho14ckthxlY9d/ah/ae0r4u/ttaj478P6bNp/gXR9cij8JaMtulm2maFZzAWNt5SMyRy+QitIQzb55JZGZmdmP0b4Z/wCCnvwb+Gvx9+N3irTfAHjXxNY/tFapeReKjq11BZXmkaHqL6i2pWNn5LsksjG7s5Y5JsKsunxMUBClfhX/AIQ/V/8AoE6n/wCAsn+FH/CH6v8A9AnU/wDwFk/wqK2ApVIqE72Sa3to7XXz5Vf/AILCMuWTkt3b8L2+67P0L0n/AILkaB4E0LWLjQfAmqahrfiyxuJNbtdfkt7vSJ7qfTtD06ezaIANNp88Gl3Sybikuy9VFIaMzPB43/4LKeBvFXj/AEnX7Hw/8WPDdv4X8Sm+07QtM8SRR6bqunvrOm6mf7R3KWuLlFsPI9JBFYuXT7MVk/Pv/hD9X/6BOp/+Asn+FH/CH6v/ANAnU/8AwFk/wo+o0ufn1v6/18u13bdmTpxcXB7Nt/Nqzfz/AD+R7v8AtwftxWn7X/gzwLp8Phew8M3HhG+1+5lXT7WG0tLhNQvhcx7YogAJFUbXY/eODXg91/yKVl/1+XP/AKLt6X/hD9X/AOgTqf8A4Cyf4U/WLKbTPDllBcxSW8/2m4kMUi7ZApSABip5AJVgD0O0+hrajRhRpqnT2R0VKsqkueW5ToqPzqK2MyIrmk8sf5FFFSSHlj/Io8sf5FFFAB5Y/wAijyx/kUUUABQAf/Wo24FFFADqKKKm5R//2Q=="},9662:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaAB8DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Gx83/wBavqD9kP8A4JI/Fj9sH4aTePreTwb8Ofhnb3Js38a+PNcj0HQ5JwWDJHLIC8pUo4YxRuqlGUkMCK8n/ZX/AGcm/ap+Oeh+AofGXgrwPeeIpvs1lqXiq7uLTTHmOBHE0sMMrRs5OFZ1CE4BYEgV9/f8HNvwquv2f/jb8NfhnY+NvBt14F+H/hGx0fw74K0a5uDd6IqQIbi9vYPJWCOW5mMhB86SZ0VHYAEY/RMXipurGhT0bOWMdLs+Kf22v2D/ABH+wt4t0PS9d8VfDXxlB4ksG1PTdR8G+JIdZtbi3DmPzCV2yIpcFVZ0UOVcKWKMB4i0fyn5d2Mcev8Anr+Br9F/+Dcn4F/s+fH79rnUdL+NXhvxR401C30jUNQs9PNhBJ4Z02zgtZJLm/1CT7QtwzDIjijjhdVkkRyScGP4y/auf4V3Xxz1yb4M/wDCZJ8PLqbztMtvFdtb2+pWKtljA5hnmSRUPCuWDsMblDAlqw2MvVdCW667IJR6nnIn/dEN/EPm9/15yR07Yz1r6B/Y/wDix8B7v4i+JL79p/w78WPHlvrEEKWeqeGtdhTUNPkVj5sskdyALliojVd0qKoWTKuWVo/niiu+rhFJ8jbv36kn3Z8Sf+CmHwj/AGd/2d/GHwx/ZN+HfjDwWPiRALDxT488Y6pFdeKL3T8hm0+3FrtitIXYESbCfMVyCAQpX4XSRVZdvuB7flUbdaKww+Fp0puMV/mB/9k="},7697:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaAB4DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8LvBXhDVPiB4x0nQtDsbvVtZ1q8hsNPs7aMvNd3MrhIoowMlnZ2VQAMkkV+n/APwSe/4NpvHX7XnxP+IGj/HTRfiZ8HdL8I2sMdpcvpKwrql5K5JWGSZDFKiouWMW5fmT5vmyPj//AIJHfELx18J/+CjHwt1z4a+Abf4meN7LU3XTfD09u84ut9vLHLJ8pAUxQtJKJWIWLyt7EKhr9vf+DqT/AIKQ/H79huy+F+i/CnVtQ8E+GfFi3c2p+IrK1Vrie5iaMxWYmkVhEChMjBSHkwRuCqwb7fNMVWdZYelZN9TnhG6uz8h/+ChX/BE/4w/shftD/FTRfDvgH4geKPhv8PYjq6eLW0aX7E2lFPM85pwvlsUG8OFPBhkOMAkfFTJhR/D+P9e9f1Ufsc/ts/tEfG3/AIN7774rat4B/wCFk/GL+x76HTNLvtO8keLLUT+Ul29suzzgbcvIY4tn2gQ4QgyA1/LHfyyG/mLRfZ5N7b4lfyliOc7QOwBJAB6YPJ7b5Tj6lVulU1cewTj1R3n7If7Ufin9i39pTwf8TvB8yw+IPCN+l3bozMsV0hDJJBJsZS0csbSRuAcMjsK/ef8A4Je/8HNnhf8Abd8Z/ELw9+1FD8H/AAB4Vht7bUPDqXCSG3nAkKvb3D3DyRySLmJlIWPkOcHgD+dCIZkX/eFWQP3ee+xzn8RWmYYGlXdpLXv1JjNp2P22/wCCjv8AwdifELw58cvix8P/AIP6f4DvPh+bN9D8MeKrNp31KGVoVV7+KUP5LEOzmNDFhdsZJcqwb8RJp2uCS+99x3k7jkk57kH3PuTVeCRjAo3N+dOrfAYOnQj+7WvcUpNn/9k="},807:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg"},7083:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg"},790:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg"},7164:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg"},5071:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAdCAYAAAC5UQwxAAAACXBIWXMAAA5NAAAOTQFG1WgJAAABxElEQVRIie2WP0vDQBjGn7YaLFnMDRak4NkOToJg9oL6GboGOpR+BCdRJz+COBS69iMoLWTv0tHBNIWi4JB0KcoV0SHcEZO79FqkOvhsL5e73/vn3veSy+cPP7FG5dcJ+wf+LpASBscOQQlTrutoQ+ejdn0Cxw4BAH5g4PRuH35gCFCvOQIlDK5notEti7WVgP2Wh1plJuz4gZQwPJ0/Ckeu7kvwAwOUMCU0M6VJWGdgwfVMYScdcT1TRKySEpiEAYBjhyK1ALBnzQFE0dWqMxExJUxZUyWw0S0rveSiVnQoJQzOcfgtvaqUpmrYrk9SkcV1cfYKPzBS0fKI/MDIdDaXnKWOHaJdnwj75LYibFWaOgMrgoUGrh92lDBAEiHfzCHj6SaqNweghEmj7wwsrfRzSWvID4nXQVaXZWGAJKUqxZs/Ccvqu6S0RlsWrN/y0GuOMi/aUsAsGK+pqr4yFXK50uUqMAAYvmzhaPcd1Jpju/iBWmWG4XMR41CdXiVwEQwApm8FuJ65FFQK1IGtCk3VkBKWGtiLrj6fLnyw87dTJmlb8InP3zdd8csDRBNKG8g36/bWMvu0G/+n9Hd/ov6BuvoCw/n+J9ZuJIUAAAAASUVORK5CYII="},5048:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAYABkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8K/DHhbUPGviLT9I0mzudS1XVrqOys7O1iaae5mkYJHGiKCWZmIAUAkk8Cvqq+/4JYaL8O7ybw78R/wBpD4G/Dv4jLFufwte3Go6g+mShSXt7+8s7SW1tplJjGwSyEMWBwyMtH/BD/wA+H9v7S5NLghn8Yf8ACMeJf+EOE0iIo13+xL37AVD8NL5+wRqPm8xlK/Mormf2f/Bt9rP7Cf7UGt3nijU9JuNBm8MLdaSUh/4ncs2pyofPaVDODEQz7I2QFsl87Qtfo1WtUlU9nF8vmcZ5j+05+yr4y/ZF+Jn/AAi3jWxtra8ms4dU0+8sruO+0/WbCbJgvrS5iLRz28gGVkU4yCpwyso8++yt6f8Ajy/419e/tPx3w/4JC/syt4s3tr03iTxWfC/mOS6eHAbABWU8iP7eb0w5yCBNtbOVHyDmT0t//HP8K3wuIc46gXPCnizU/AviOw1nRdQvNK1jSrhLuyvLSVoZ7WVGDI6OpDKysAQQcg9K+ttf/wCCs+i/FS/fxD8Sf2afgP8AED4hYMreJp7XUNLfU7kn5ri+tbK6ht7l2G0HCR5I3Z3EmiirqYanVfvoDwH9qT9rHxt+2N8U28XeOtQtr7UY7OLTLK3s7KGxsdKsIQVhsraCJVSGCNThUUcZYnLMWPnv2x/Vf++BRRXTQpRhDligP//Z"},1412:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg"},6200:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg"},6490:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg"},1623:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg"},7317:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg"}}]); \ No newline at end of file diff --git a/assets/js/4c80fdcb.d2ab6915.js b/assets/js/4c80fdcb.d2ab6915.js new file mode 100644 index 000000000000..b4fc4a337025 --- /dev/null +++ b/assets/js/4c80fdcb.d2ab6915.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8511],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>g});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={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,o=e.mdxType,a=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),f=o,g=p["".concat(c,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(g,i(i({ref:t},u),{},{components:r})):n.createElement(g,i({ref:t},u))}));function g(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4155:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={},i="Ethereal Engine",l={unversionedId:"creator/tutorials/ethereal_engine/readme",id:"creator/tutorials/ethereal_engine/readme",title:"Ethereal Engine",description:"In this section you will various tutorials for Ethereal Engine.",source:"@site/docs/2_creator/5_tutorials/1_ethereal_engine/readme.md",sourceDirName:"2_creator/5_tutorials/1_ethereal_engine",slug:"/creator/tutorials/ethereal_engine/",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/1_ethereal_engine/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Tutorials",permalink:"/etherealengine-docs/docs/creator/tutorials/"},next:{title:"Unity Bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge"}},c={},s=[],u={toc:s},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-engine"},"Ethereal Engine"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/530a89a7.f88b4cdd.js b/assets/js/530a89a7.f88b4cdd.js new file mode 100644 index 000000000000..11b0b61665e0 --- /dev/null +++ b/assets/js/530a89a7.f88b4cdd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5111],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>g});var n=r(7294);function o(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 a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},s=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={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,o=e.mdxType,i=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,g=p["".concat(l,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(g,a(a({ref:t},s),{},{components:r})):n.createElement(g,a({ref:t},s))}));function g(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u<i;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},1869:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const i={hide_table_of_contents:!0},a="Unity Bridge",c={unversionedId:"creator/tutorials/ethereal_engine/unity_bridge",id:"creator/tutorials/ethereal_engine/unity_bridge",title:"Unity Bridge",description:"",source:"@site/docs/2_creator/5_tutorials/1_ethereal_engine/01_unity_bridge.md",sourceDirName:"2_creator/5_tutorials/1_ethereal_engine",slug:"/creator/tutorials/ethereal_engine/unity_bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/1_ethereal_engine/01_unity_bridge.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/"},next:{title:"Unreal Bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge"}},l={},u=[],s={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"unity-bridge"},"Unity Bridge"),(0,o.kt)("iframe",{width:"100%",height:"600",src:"https://www.youtube.com/embed/uNnCZ_T-qo0?list=PLE345Qm2tFnXRkHLKf1Hz3FRNUdt14vJK&showinfo=0&rel=0",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/54e37525.176276c0.js b/assets/js/54e37525.176276c0.js new file mode 100644 index 000000000000..956ef700bd4f --- /dev/null +++ b/assets/js/54e37525.176276c0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6718],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||r;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c<r;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5888:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const r={hide_table_of_contents:!0},i="Writing Reasonable & Testable Code",s={unversionedId:"creator/testing/reasonable_code",id:"creator/testing/reasonable_code",title:"Writing Reasonable & Testable Code",description:"Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application.",source:"@site/docs/2_creator/6_testing/2_reasonable_code.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/reasonable_code",permalink:"/etherealengine-docs/docs/creator/testing/reasonable_code",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/2_reasonable_code.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Testing Basics",permalink:"/etherealengine-docs/docs/creator/testing/testing_intro"},next:{title:"Writing Good Tests",permalink:"/etherealengine-docs/docs/creator/testing/test_driven_development"}},l={},c=[{value:"Example",id:"example",level:3},{value:"Code Composition / Decomposition",id:"code-composition--decomposition",level:2},{value:"Example",id:"example-1",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"writing-reasonable--testable-code"},"Writing Reasonable & Testable Code"),(0,a.kt)("p",null,"Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application."),(0,a.kt)("p",null,"In the functional programming (FP) paradigm, pure functions are functions which do not mutate any existing state of ",(0,a.kt)("em",{parentName:"p"},"any")," scope. Since we are not in a fully functional paradigm, a focus on these qualities of functions can be priceless: stateless functions with ",(0,a.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Referential_transparency"},"referential transparency"),"."),(0,a.kt)("p",null,"Stateless means that the function itself has ",(0,a.kt)("strong",{parentName:"p"},"no memory of the past"),". Referential transparency means that the function is only operating on the parameters, and ",(0,a.kt)("strong",{parentName:"p"},"nothing else")," (no global state access, etc)."),(0,a.kt)("p",null,"These types of functions may (arguably) mutate parameter state, but may only operate on the given parameters. State residing outside of the scope of a stateless function should ",(0,a.kt)("strong",{parentName:"p"},"never be depended on or mutated"),". This will ensure that the function holds no inherent state of its own, and therefore will exhibit the behavior of being referentially transparent and ",(0,a.kt)("strong",{parentName:"p"},"idempotent"),". "),(0,a.kt)("p",null,"Idempotency is a quality of any function which can be executed several times without changing the output for a specific input. Idempotent functions can be thought of as mappings from one input to one output. "),(0,a.kt)("p",null,"All of this combined makes functions extremely simple to reason about, very reusable, and easy to test! Three gulls, one scone."),(0,a.kt)("h3",{id:"example"},"Example"),(0,a.kt)("p",null,"Here is an example of a function that does not exhibit referential transparency, nor is it stateless:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"let y = 3\nconst someFunction = x => {\n x += y\n y++\n return x\n}\n\nsomeFunction(3) // => 6\nsomeFunction(3) // => 7\nsomeFunction(3) // => 8\n")),(0,a.kt)("p",null,"This function is also not idempotent. Same input, different output! Not good for reasonable code, difficult to predict."),(0,a.kt)("p",null,"Written as a stateless, idempotent function with referential transparency:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const someFunction = (data, x) => {\n x += data.y\n data.y++\n return x\n}\n\nsomeFunction({ y: 3 }, 3) // => 6\nsomeFunction({ y: 3 }, 3) // => 6\nsomeFunction({ y: 3 }, 3) // => 6\n")),(0,a.kt)("p",null,"The newly written function now holds no inherent state of its own and does not operate on any data that was not passed into the function as explicit arguments. It is also idempotent: same input, same output! Very reasonable and easy to predict."),(0,a.kt)("h2",{id:"code-composition--decomposition"},"Code Composition / Decomposition"),(0,a.kt)("p",null,"We must now capture the process of decomposing a program into smaller pieces that are more reusable, more reliable, and easier to understand. Then we can combine each individual piece to form an entire program that is easier to reason about as a whole. FP tends to follow this fundamental principle."),(0,a.kt)("p",null,"FP falls under the umbrella of declarative programming paradigms: it expresses a set of operations without revealing how they\u2019re implemented or how data flows through them. Unlike imperative programming, declarative programming separates program description from evaluation. It focuses on the use of expressions to describe what the logic of a program is without necessarily specifying its control flow or state change."),(0,a.kt)("p",null,"These two paradigms can be utilized to form powerful and extremely testable functions and compositions which support a sturdy codebase. Write functions imperatively, then compose them together declaratively!"),(0,a.kt)("h3",{id:"example-1"},"Example"),(0,a.kt)("p",null,"Using the previous unit/integration test examples, lets see what the algorithm would look like if written imperatively:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const algorithm = x => {\n // first, add two\n x += 2\n // then, multiply by three\n x *= 3\n // finally, divide by two\n x /= 2\n return x\n}\n")),(0,a.kt)("p",null,"Rewritten declaratively, as demostrated before but with a newly introduced ",(0,a.kt)("inlineCode",{parentName:"p"},"pipe")," function (a standard function in FP):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const addTwo = x => x + 2\nconst multThree = x => x * 3\nconst halve = x => x / 2\n\nconst algorithm = pipe(addTwo, multThree, halve)\n\nalgorithm(4) // => 9\n")),(0,a.kt)("p",null,"As you can see, the imperative function has no reusable parts, but the declarative version does! This is a simple example, but in larger-scale functions and systems this simple distinction can be a powerful tool in writing reasonable, testable, and reusable code. Bonus: the code is ",(0,a.kt)("em",{parentName:"p"},"self documenting"),". No need for comments here. Just pure, self-descriptive functions!"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/58222842.91787d57.js b/assets/js/58222842.91787d57.js new file mode 100644 index 000000000000..0be96823956a --- /dev/null +++ b/assets/js/58222842.91787d57.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8718],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=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=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=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"]),c=d(n),p=i,m=c["".concat(s,".").concat(p)]||c[p]||h[p]||o;return n?a.createElement(m,l(l({ref:t},u),{},{components:n})):a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,l=new Array(o);l[0]=p;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[c]="string"==typeof e?e:i,l[1]=r;for(var d=2;d<o;d++)l[d]=n[d];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}p.displayName="MDXCreateElement"},765:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const o={},l="Ethereal Engine on AWS",r={unversionedId:"host/devops_deployment/AWS_setup",id:"host/devops_deployment/AWS_setup",title:"Ethereal Engine on AWS",description:"The value RELEASE_NAME referenced throughout this guide is the name of the deployment, e.g. dev or prod.",source:"@site/docs/1_host/2_devops_deployment/2_AWS_setup.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/AWS_setup",permalink:"/etherealengine-docs/docs/host/devops_deployment/AWS_setup",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/2_AWS_setup.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on Minikube",permalink:"/etherealengine-docs/docs/host/devops_deployment/minikube"},next:{title:"Installing Projects",permalink:"/etherealengine-docs/docs/host/devops_deployment/installing_projects"}},s={},d=[{value:"Ways of serving client files in production",id:"ways-of-serving-client-files-in-production",level:2},{value:"Serve client files from client pods",id:"serve-client-files-from-client-pods",level:3},{value:"Serve client files from API pods",id:"serve-client-files-from-api-pods",level:3},{value:"Serve client files from Storage Provider (S3 + Cloudfront)",id:"serve-client-files-from-storage-provider-s3--cloudfront",level:3},{value:"Create EKS cluster with four nodegroups",id:"create-eks-cluster-with-four-nodegroups",level:2},{value:"Enable EBS CSI Addon (if EKS version is 1.23 or later)",id:"enable-ebs-csi-addon-if-eks-version-is-123-or-later",level:4},{value:"Install Cluster Autoscaler (optional)",id:"install-cluster-autoscaler-optional",level:4},{value:"Create launch template",id:"create-launch-template",level:4},{value:"Create nodegroup for instanceservers",id:"create-nodegroup-for-instanceservers",level:4},{value:"Create nodegroup for redis",id:"create-nodegroup-for-redis",level:4},{value:"Create nodegroup for builder",id:"create-nodegroup-for-builder",level:4},{value:"Create ECR repositories for built images.",id:"create-ecr-repositories-for-built-images",level:2},{value:"Create IAM Roles for S3/SES/SNS (or a single admin role)",id:"create-iam-roles-for-s3sessns-or-a-single-admin-role",level:2},{value:"Creating an IAM role",id:"creating-an-iam-role",level:3},{value:"IAM Roles to create",id:"iam-roles-to-create",level:3},{value:"Creating new credentials for an IAM user",id:"creating-new-credentials-for-an-iam-user",level:3},{value:"Create RDS box",id:"create-rds-box",level:2},{value:"Accessing RDS box from an external machine",id:"accessing-rds-box-from-an-external-machine",level:3},{value:"Create RDS instance",id:"create-rds-instance",level:3},{value:"Edit security group to allow instanceserver traffic into VPC",id:"edit-security-group-to-allow-instanceserver-traffic-into-vpc",level:2},{value:"Create Route 53 Hosted Zone and set up ACM certificates",id:"create-route-53-hosted-zone-and-set-up-acm-certificates",level:2},{value:"Purchase and register domain through Route53 (optional)",id:"purchase-and-register-domain-through-route53-optional",level:3},{value:"Create Route 53 Hosted Zone",id:"create-route-53-hosted-zone",level:3},{value:"Point external registrar subdomains to use Route53 Nameservers (only if your domain is registered outside Route53)",id:"point-external-registrar-subdomains-to-use-route53-nameservers-only-if-your-domain-is-registered-outside-route53",level:4},{value:"Create certificates with ACM",id:"create-certificates-with-acm",level:3},{value:"If you are serving client files from client or API pods",id:"if-you-are-serving-client-files-from-client-or-api-pods",level:4},{value:"If you are serving client files from the Storage Provider",id:"if-you-are-serving-client-files-from-the-storage-provider",level:4},{value:"Install Agones, ingress-nginx, and a copy of redis for each deployment",id:"install-agones-ingress-nginx-and-a-copy-of-redis-for-each-deployment",level:2},{value:"Install Agones",id:"install-agones",level:3},{value:"Install redis for each deployment",id:"install-redis-for-each-deployment",level:3},{value:"Installing redis as part of Ethereal Engine chart (not recommended for production)",id:"installing-redis-as-part-of-ethereal-engine-chart-not-recommended-for-production",level:4},{value:"Install ingress-nginx",id:"install-ingress-nginx",level:3},{value:"Set up Simple Email Service (optional)",id:"set-up-simple-email-service-optional",level:2},{value:"Create SMTP credentials",id:"create-smtp-credentials",level:3},{value:"Move SES out of Sandbox",id:"move-ses-out-of-sandbox",level:3},{value:"Verifying test emails",id:"verifying-test-emails",level:4},{value:"Set up Simple Notification Service (optional)",id:"set-up-simple-notification-service-optional",level:2},{value:"Set up S3 bucket for static resources and Cloudfront distribution",id:"set-up-s3-bucket-for-static-resources-and-cloudfront-distribution",level:2},{value:"Create S3 bucket",id:"create-s3-bucket",level:3},{value:"Create Cloudfront distribution",id:"create-cloudfront-distribution",level:3},{value:"Legacy cache settings",id:"legacy-cache-settings",level:4},{value:"Set up DNS records",id:"set-up-dns-records",level:2},{value:"Create GitHub fork of Ethereal Engine repository.",id:"create-github-fork-of-ethereal-engine-repository",level:2},{value:"Grant EKSUser access to cluster",id:"grant-eksuser-access-to-cluster",level:2},{value:"Deploy to EKS using Helm",id:"deploy-to-eks-using-helm",level:2},{value:"Fill in Helm config file with variables",id:"fill-in-helm-config-file-with-variables",level:3},{value:"Configuration variables of note",id:"configuration-variables-of-note",level:3},{value:"<api/instanceserver/taskserver>.extraEnv.AUTH_SECRET",id:"apiinstanceservertaskserverextraenvauth_secret",level:4},{value:"<api/client/taskserver>.affinity.nodeAffinity",id:"apiclienttaskserveraffinitynodeaffinity",level:4},{value:"builder.extraEnv.PRIVATE_ECR",id:"builderextraenvprivate_ecr",level:4},{value:"(everything).image.repository",id:"everythingimagerepository",level:4},{value:"GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET",id:"github_client_idgithub_client_secret",level:4},{value:"Run Helm install",id:"run-helm-install",level:3},{value:"Kick off GitHub Actions",id:"kick-off-github-actions",level:2},{value:"Overview of the build process",id:"overview-of-the-build-process",level:3},{value:"Install Elastic Search and Kibana using Helm for Server Logs",id:"install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Upgrading an existing Helm deployment",id:"upgrading-an-existing-helm-deployment",level:3}],u={toc:d},c="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(c,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"ethereal-engine-on-aws"},"Ethereal Engine on AWS"),(0,i.kt)("p",null,"The value ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," referenced throughout this guide is the name of the deployment, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"dev")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"prod"),"."),(0,i.kt)("h2",{id:"ways-of-serving-client-files-in-production"},"Ways of serving client files in production"),(0,i.kt)("p",null,"There are multiple ways to serve built client files in a production environment.\nYou should decide how you want to serve them now, because a few later steps will be affected\nby that choice, and changing your AWS configuration after everything has been set up one way\nis a little tricky:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"From client pods (separate from API pods)"),(0,i.kt)("li",{parentName:"ul"},"From API pods"),(0,i.kt)("li",{parentName:"ul"},"From the storage provider, such as S3/Cloudfront")),(0,i.kt)("h3",{id:"serve-client-files-from-client-pods"},"Serve client files from client pods"),(0,i.kt)("p",null,"This is the default method. The Helm charts assume that the deployment will have client pods\nto serve client files, and the client ingress will point traffic to the client pods. The client\nURL will be pointed to the EKS Load Balancer, and you will not need a separate client certificate."),(0,i.kt)("p",null,"This option gives you slightly more flexibility in scaling a deployed cluster than serving\nfrom the API pods, since you can scale the number of API and client pods independently."),(0,i.kt)("p",null,"Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture\nof how projects are built and served, and serving from the Storage Provider may end up being the only\nallowable option."),(0,i.kt)("h3",{id:"serve-client-files-from-api-pods"},"Serve client files from API pods"),(0,i.kt)("p",null,"This will make your builder build and serve the client service from the API pods. The Helm\nchart will not have a client deployment, serviceaccount, configmap, etc., and the client\ningress will point to the API pods. The client URL will be pointed to the EKS Load Balancer,\nand you will not need a separate client certificate."),(0,i.kt)("p",null,"To enable this, set client.serveFromApi to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," in your Helm config file when you are configuring it.\nThis needs to be applied to both the builder deployment and the main deployment, but if you set this\nbefore deploying anything, it will be applied to both."),(0,i.kt)("p",null,"This option can save you some money by requiring fewer nodes in order to host all of the\nAPI+client pods you desire, as you do not need capacity for separate client pods. It offers\nslightly less flexibility in scaling since you cannot scale the number of API and client pods\nseparately; more client capacity would require more API capacity, and vice versa. It also\nwill result in slightly longer deployment times, as the combined API+client Docker images\nare larger than an API-only or client-only image (though smaller than the sum of the two\nseparate images), which will mean a few more seconds to download to each node."),(0,i.kt)("p",null,"Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture\nof how projects are built and served, and serving from the Storage Provider may end up being the only\nallowable option."),(0,i.kt)("h3",{id:"serve-client-files-from-storage-provider-s3--cloudfront"},"Serve client files from Storage Provider (S3 + Cloudfront)"),(0,i.kt)("p",null,"This will make the client build process push all of its built files to S3 and serve them via\nCloudfront. Static resources will also be served from the client domain instead of a separate\nresources domain. The client URL will be pointed to the Cloudfront distribution, not the EKS Load\nBalancer; only API and instanceserver traffic will go to the EKS cluster. You will need a separate\nclient certificate, but you will not need a resources domain certificate."),(0,i.kt)("p",null,"As of this writing, only Amazon S3/Cloudfront is supported as a storage provider\nin a cloud environment."),(0,i.kt)("p",null,"To enable this, set builder.extraEnv.SERVE_CLIENT_FROM_STORAGE_PROVIDER to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," in the\nHelm config file when you are configuring it. Also make sure that builder.extraEnv.STORAGE_PROVIDER is set to ",(0,i.kt)("inlineCode",{parentName:"p"},"s3"),"."),(0,i.kt)("p",null,"This option can greatly speed up the time it takes for users to fully load your worlds,\nsince every client file can be served from a CDN close to them, rather than\nhaving to fetch them all from the closest physical server. It will also slightly speed up build times and deployment\ntimes since the client build does not need to be pushed to a Docker repo (though a cache of the build will still\nbe pushed to speed up future builds)."),(0,i.kt)("h2",{id:"create-eks-cluster-with-four-nodegroups"},"Create EKS cluster with four nodegroups"),(0,i.kt)("p",null,"You first need to set up an EKS cluster for Ethereal Engine to run on.\nWhile this can be done via AWS' web interface, the ",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl")," CLI\nwill automatically provision more of the services you need automatically,\nand is thus recommended."),(0,i.kt)("p",null,"First, follow ",(0,i.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html"},"these instructions"),"\nfor setting up aws-cli, eksctl, and configuring aws-cli with your AWS credentials.\nYou should also set up kubectl and Helm, as we will be using that to install multiple codebases from Charts."),(0,i.kt)("p",null,"Next run the following command:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"eksctl create cluster --name <name> --version <version> --region <region> --managed --nodegroup-name <name> --node-type <instance type> --nodes <target_node_number> --nodes-min <minimum_node_number> --nodes-max <maximum_node_number> --spot")),(0,i.kt)("p",null,"This will create an EKS cluster with a managed nodegroup in the specified region, including automatically\ncreating subnets, making a VPC, and more. It may take up to 15 minutes to complete."),(0,i.kt)("p",null,"You can also use the flag ",(0,i.kt)("inlineCode",{parentName:"p"},"--zones <zone1>,<zone2>")," to specify which Availability Zones the cluster\nshould set up in. Some regions have zones that are unavailable, but which eksctl will try to\nuse if --zones is not specified, leading to the setup to fail. As an example, us-west-1 (as of this\nwriting) does not have any resources available in us-west-1b; if you are setting up in us-west-1,\nyou would want to use ",(0,i.kt)("inlineCode",{parentName:"p"},"--zones us-west-1a,us-west-1c"),"."),(0,i.kt)("p",null,"Note that the region matters for almost all services in AWS. The default region is 'us-east-1',\nbut if you make the cluster in any other region, you'll need to make sure you're creating certs,\nDNS records, etc. in the same region."),(0,i.kt)("p",null,"As of this writing, the API and client are configured to run on a nodegroup named 'ng-1'.\nIf you name it something else, be sure to change the NodeAffinity in the configuration file. This is one of ",(0,i.kt)("strong",{parentName:"p"},"four"),"\nnodegroups that will be created for various services to run on."),(0,i.kt)("p",null,"Make sure to increase the maximum node limit, as by default target, minimum, and maximum are\nset to 2, and Ethereal Engine's setup will definitely need more than two nodes if you've configured\nthem to use relatively small instance types such as t3a.medium."),(0,i.kt)("h4",{id:"enable-ebs-csi-addon-if-eks-version-is-123-or-later"},"Enable EBS CSI Addon (if EKS version is 1.23 or later)"),(0,i.kt)("p",null,"Follow the instructions ",(0,i.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/eks/latest/userguide/managing-ebs-csi.html"},"here"),"\nto enable an EKS addon that's required for any cluster that will have Persistent Volumes, which an\nEthereal Engine deployment cluster will."),(0,i.kt)("h4",{id:"install-cluster-autoscaler-optional"},"Install Cluster Autoscaler (optional)"),(0,i.kt)("p",null,"While not necessary, it can be useful to have an autoscaler installed in the cluster to increase\nthe number of nodes available for pods when the cluster has high traffic and to decrease that\nnumber when it has low traffic."),(0,i.kt)("p",null,"Follow ",(0,i.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/eks/latest/userguide/autoscaling.html#cluster-autoscaler"},"these instructions"),"\nto set up the autoscaler. Any managed nodegroups created in the following steps should by default be\ntagged such that the autoscaler can control them, so no further action should be required."),(0,i.kt)("p",null,"Note that there is some lag time on scaling up and down. It generally takes about 5 minutes from\nthe time that the autoscaler sees the need to add more nodes before those nodes have been spun up,\nthe appropriate Docker image has been installed onto them, and they are ready to be used. It takes about\n15 minutes for the autoscaler to actually remove nodes that are deemed superfluous, as a hedge against\nthe recent high traffic picking up again."),(0,i.kt)("p",null,"The OIDC provider that was created in the prior step, installing the EBS CSI Addon, can be re-used in this step."),(0,i.kt)("h4",{id:"create-launch-template"},"Create launch template"),(0,i.kt)("p",null,"Go to EC2 -> Launch Templates and make a new one. Name it something like 'etherealengine-production-instanceserver'.\nMost settings can be left as-is, except for the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Storage -> Add a volume, set the size to ~20GB, and for Device name select '/dev/xvda'."),(0,i.kt)("li",{parentName:"ul"},"Network Interfaces -> Add one, and under 'Auto-assign public IP' select 'Enable'")),(0,i.kt)("h4",{id:"create-nodegroup-for-instanceservers"},"Create nodegroup for instanceservers"),(0,i.kt)("p",null,"Go to the AWS website, then go to EKS -> Clusters -> click on the cluster you just made -> Configuration -> Compute.\nYou should see one managed nodegroup already there; clicking on its name will open up information\nand editing, though you can't change the instance type after it's been made."),(0,i.kt)("p",null,"Back at the Compute tab, click on Add Node Group. Pick a name (something like ng-instanceservers-1 is recommended),\nselect the IAM role that was created with the cluster (it should be something like ",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>"),"),\ntoggle the Use Launch Template toggle and select the launch template you made in the previous step,\nthen click Next. On the second page, Choose the instance type(s) you'd like for the group,\nset the minimum/maximum/desired scaling sizes, and hit Next (t3(a).smalls are recommended).\nThere may be connection issues with instanceserver instances in private subnets, so remove all of the private\nsubnets from the list of subnets to use, and make sure that public subnets are being used (sometimes\nthe workflow only selects private subnets by default). Hit Next, review everything, and click Create."),(0,i.kt)("h4",{id:"create-nodegroup-for-redis"},"Create nodegroup for redis"),(0,i.kt)("p",null,"Redis should get its own nodegroup to isolate it from any other changes that might be made to your cluster.\nAs with the instanceserver nodegroup, it's not strictly necessary, but can prevent various other things from\ngoing down due to the redis servers getting interrupted."),(0,i.kt)("p",null,"Back at the Compute tab, click on Add Node Group. Pick a name (the default config in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.minikube.template.values.yaml"},"ethereal-engine-ops")," assumes\na name of 'ng-redis-1'), select the IAM role that was created with the cluster\n(it should be something like ",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>"),"),\ntoggle the Use Launch Template toggle and select the launch template used to make the initial nodegroup,\nthen click Next. On the second page, Choose the instance type(s) you'd like for the group,\nset the minimum/maximum/desired scaling sizes (you can probably get away with a single t3(a).small, but it's recommended\nto have at least two nodes so that one going down doesn't kill the entire deployment from a lack of redis), and hit Next.\nThe default subnets should be fine, so hit Next, review everything, and click Create."),(0,i.kt)("h4",{id:"create-nodegroup-for-builder"},"Create nodegroup for builder"),(0,i.kt)("p",null,"The full Ethereal Engine stack needs a builder server within the cluster in order to bundle and build\nEthereal Engine projects into the codebase that will be deployed. This should run on its own nodegroup\nthat has a single node - only one copy of the builder should ever be running at a time, and\ndue to the high memory needs of building the client service, a box with >8 GB of RAM is needed."),(0,i.kt)("p",null,"Back at the Compute tab, click on Add Node Group. Pick a name (something like ",(0,i.kt)("inlineCode",{parentName:"p"},"ng-dev-builder-1")," is recommended) and\nselect the IAM role that was created with the cluster (it should be something like\n",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>"),"). You don't need to use any Launch Template\nfor this nodegroup. Click Next."),(0,i.kt)("p",null,"On the second page, you can change the Capacity Type to ",(0,i.kt)("inlineCode",{parentName:"p"},"Spot")," if you want to in order to save money; the builder\nservice will likely not be running very often or for too long, so the odds of it getting interrupted by Spot instance\noutages are low, and it can always re-build if that does happen. Set the Disk Size to 50 GB; it takes a good deal of\ndisk space to install and build the Ethereal Engine codebase, and the default 20 GB will almost certainly not be enough."),(0,i.kt)("p",null,"For Instance Types, you need to only select types that have more than 8 GB; t3a.xlarge are the cheapest that fit\nthis criteria. If you were to pick something with 8GB, it's highly likely that most builds would crash the node,\nas Kubernetes tends to restart nodes if they get anywhere near memory capacity.\nUnder Node Group Scaling Configuration, set all three ",(0,i.kt)("inlineCode",{parentName:"p"},"nodes")," values to 1. We only want a single copy of the builder\nat any given time, and running multiple powerful boxes can get pricey. Click Next."),(0,i.kt)("p",null,"You can leave the subnets on the next page alone and click Next. On the last page, click Create."),(0,i.kt)("h2",{id:"create-ecr-repositories-for-built-images"},"Create ECR repositories for built images."),(0,i.kt)("p",null,"The Ethereal Engine deployment process will be building multiple Docker images, and those need to be stored somewhere.\nIn AWS, that somewhere is ",(0,i.kt)("a",{parentName:"p",href:"https://us-west-1.console.aws.amazon.com/ecr/get-started"},"Elastic Container Registry"),".\nYou need to make those repositories in the same AWS region where the EKS cluster is running."),(0,i.kt)("p",null,"Go to the ECR link above and click Get Started under Create a Repository. If you're very concerned about any of your\nEthereal Engine project codebase(s) getting out, you can choose Private for Visibility Settings, but normally Public is fine.\nYou'll be needing to create multiple repositories for each deployment, e.g. several repos for a ",(0,i.kt)("inlineCode",{parentName:"p"},"dev")," deployment,\nseveral more for a ",(0,i.kt)("inlineCode",{parentName:"p"},"prod")," deployment, etc."),(0,i.kt)("p",null,"Assuming you're first doing a ",(0,i.kt)("inlineCode",{parentName:"p"},"dev")," deployment, name the first repo ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-<RELEASE_NAME>-builder")," under Repository\nName, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-builder"),". You shouldn't need to change any other settings, though if you're using a Private\nrepo and want to turn on Tag Immutability, that's fine. The image tags that are generated should never collide, but it\nwill prevent any manual overwriting of a tag. Click Create Repository."),(0,i.kt)("p",null,"You will need to make four more repos for each of the services that are deployed as part of the Ethereal Engine stack -\n",(0,i.kt)("inlineCode",{parentName:"p"},"api"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"client"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"instanceserver")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"taskserver"),", which are also in the form ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-<RELEASE_NAME>-<service_name>"),".\ne.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-api"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-client"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-instanceserver")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-taskserver"),".\nEverything else can be left alone for those, too."),(0,i.kt)("p",null,"On the ",(0,i.kt)("a",{parentName:"p",href:"https://us-west-1.console.aws.amazon.com/ecr/repositories"},"repositories page"),", you should see both of\nthe repositories you made. If you don't see any, you may be on the wrong tab up top - click Private or Public to switch\nbetween them. Also check that you're in the right AWS region. You'll see a column 'URI'. If you made public repos,\nthe URIs should be in the form ",(0,i.kt)("inlineCode",{parentName:"p"},"public.ecr.aws/<identifier>/etherealengine-<RELEASE_NAME>(-builder)"),"; if you made private\nrepos, the URIs should be in the form ",(0,i.kt)("inlineCode",{parentName:"p"},"<AWS_account_id>.dkr.ecr.<AWS_region>.amazonaws.com/etherealengine-<deployment>(-builder)"),".\nTake note of everything before the ",(0,i.kt)("inlineCode",{parentName:"p"},"/etherealengine-<RELEASE_NAME>")," - you'll need to add that as a variable in later steps.\nIt will be called ",(0,i.kt)("inlineCode",{parentName:"p"},"ECR_URL")," there."),(0,i.kt)("h2",{id:"create-iam-roles-for-s3sessns-or-a-single-admin-role"},"Create IAM Roles for S3/SES/SNS (or a single admin role)"),(0,i.kt)("p",null,"Ethereal Engine interfaces with several AWS services and requires credentials for these purposes. You could make\none admin role with full access to all AWS services, but we recommend making separate, scoped roles for\neach individual service. To create a role, do the following:"),(0,i.kt)("h3",{id:"creating-an-iam-role"},"Creating an IAM role"),(0,i.kt)("p",null,"Go to IAM->Users, and click on the Add User button. For User Name, enter ",(0,i.kt)("inlineCode",{parentName:"p"},"<service>-admin"),", e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"S3-admin"),".\nCheck the box for Programmatic Access, the click on the Next:Permissions button.\nClick on 'Attach existing policies directly'. In the Filter Policies text box, you'll want to\nenter the name of the service to narrow down the policy list significantly. Then, look for the FullAccess\npolicy for that service and select that, and click the Next:Tags button. You don't need to tag it with\nanything, just click the Next:Review button, then the Create User button."),(0,i.kt)("p",null,"The following screen should show Success and have the user listed. Copy the 'Access key ID' somewhere, and\nalso click the Show toggle under 'Secret access key' and copy that elsewhere as well. You will put these\ninto the Helm config file later."),(0,i.kt)("h3",{id:"iam-roles-to-create"},"IAM Roles to create"),(0,i.kt)("p",null,"Here are the services you want to create IAM admin users for, and the associated permissions you want to\ngrant them:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"S3: ",(0,i.kt)("inlineCode",{parentName:"li"},"AmazonS3FullAccess, CloudFrontFullAccess")),(0,i.kt)("li",{parentName:"ul"},"SNS: ",(0,i.kt)("inlineCode",{parentName:"li"},"AmazonSNSFullAccess"))),(0,i.kt)("p",null,"You'll also need to create an IAM user that GitHub Actions can use to access the cluster and push/pull\nDocker images from ECR. By convention, we call this user 'EKSUser', and it needs these\npermissions: ",(0,i.kt)("inlineCode",{parentName:"p"},"AmazonEKSClusterPolicy, AmazonEKSWorkerNodePolicy, AmazonEKSServicePolicy, AmazonElasticContainerRegistryPublicFullAccess, AmazonEC2ContainerRegistryFullAccess")),(0,i.kt)("h3",{id:"creating-new-credentials-for-an-iam-user"},"Creating new credentials for an IAM user"),(0,i.kt)("p",null,"If you ever lose the secret to a user, or want to make new credentials for whatever reason, go to\nIAM->Users and click on that user. Click on the 'Security credentials' tab, and under 'Access keys' you\nshould see a button 'Create access key' and, underneath that, 0-2 existing keys with some information\nabout them and an 'x' on the far right to delete it. If there are two keys for that user, you\nmust deactivate and delete one of them before making a new one."),(0,i.kt)("p",null,"Click the Create button, then make sure to save the public and secret keys somewhere and put them into\nthe Helm config file."),(0,i.kt)("h2",{id:"create-rds-box"},"Create RDS box"),(0,i.kt)("p",null,"Ethereal Engine is backed by a SQL server. We use MariaDB in development, but it has also been run on AWS with\nAurora without issue. Most other versions of SQL should work but have not been explicitly tested."),(0,i.kt)("h3",{id:"accessing-rds-box-from-an-external-machine"},"Accessing RDS box from an external machine"),(0,i.kt)("p",null,"By default, an RDS box is only accessible from within the VPC it's located.\nIf you want to be able to connect to it from outside that VPC, you'll need to either set up a bastion box\nand SSH into that box, or make the RDS box publicly accessible."),(0,i.kt)("p",null,"Setting up a bastion box is not covered here at this time. The steps to make it public will be noted\nbelow by ",(0,i.kt)("strong",{parentName:"p"},"Make RDS public")),(0,i.kt)("h3",{id:"create-rds-instance"},"Create RDS instance"),(0,i.kt)("p",null,"Go to RDS and click the Create Database button. Most options can be left at their default values.\nUnder Settings, give a more descriptive DB cluster identifier. The Master Username can be left as admin;\nenter a Master Password and then enter it again in Confirm Password."),(0,i.kt)("p",null,"Under DB instance class, pick an option that best meets your pricing needs."),(0,i.kt)("p",null,"Under Availability and Durability, it's recommended that you leave it on the default of\nmaking an Aurora Replica in another AZ."),(0,i.kt)("p",null,"Under Connectivity, make sure that it's in the VPC that was made as part of the EKS cluster."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Make RDS public"),"\nIf you want to be able to access it externally, you should set Public Access to 'Yes'."),(0,i.kt)("p",null,"Under VPC security group, select the ones titled\n",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<EKS_cluster_name>-cluster-ClusterSharedNodeSecurityGroup-<random_string>")," and\n",(0,i.kt)("inlineCode",{parentName:"p"},"eks-clustersg-<EKS_cluster_name>-<random_string>"),"."),(0,i.kt)("p",null,"Open the top-level Additional Configuration dropdown (not the one within Connectivity). Under Database Options-> Initial Database Name,\nname the default database and save this for later use in the Helm config file."),(0,i.kt)("p",null,"Finally, click the Create Database button at the very bottom of the page."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Make RDS Public")," You will need to add a Security Group to the RDS instance that allows traffic over port\n3306 (or whatever port you chose to run it on). You can have this SG only let in traffic from your IP address(es)\nif you want to be very secure about this, or from anywhere (0.0.0.0/0) if you're less concerned about someone\ngetting access."),(0,i.kt)("p",null,"Some values to note for dev/prod.template.values.yaml:\nsql.database will be what you entered for Initial Database Name\nsql.user and sql.password will be the name and password of the admin user\nsql.host will be the Endpoint of the RDS instance/cluster; find this by going to RDS -> Databases,\nclicking on either the lone DB identifier (if made in a single AZ) or the top-level regional cluster\nidentifier (if set up in a multi-AZ deployment); the look for Endpoint (single-AZ) or, if multi-AZ,\nthe Endpoint name that has type 'Writer instance'."),(0,i.kt)("h2",{id:"edit-security-group-to-allow-instanceserver-traffic-into-vpc"},"Edit security group to allow instanceserver traffic into VPC"),(0,i.kt)("p",null,"You'll need to edit the new cluster's main security group to allow instanceserver traffic.\nOn the AWS web client, go to EC2 -> Security Groups. There should be three SGs that have\nthe node's name somewhere in their name; look for the one that is in the form\n",(0,i.kt)("inlineCode",{parentName:"p"},"eks-cluster-sg-<cluster_name>-<random_numbers>"),". It should NOT end with /ControlPlaneSecurityGroup\nor /ClusterSharedNodeSecurityGroup.\nClick on that, then the Inbound Rules tab, then click Edit Inbound Rules."),(0,i.kt)("p",null,"You'll need to add two rule sets:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Type: Custom UDP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')"),(0,i.kt)("li",{parentName:"ul"},"Type: Custom TCP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')")),(0,i.kt)("h2",{id:"create-route-53-hosted-zone-and-set-up-acm-certificates"},"Create Route 53 Hosted Zone and set up ACM certificates"),(0,i.kt)("p",null,"Before installing Nginx to the cluster, you'll need to have all of the networking squared away.\nThis requires creating the necessary SSL certificates and creating some DNS records to point\nvarious subdomains to the right place."),(0,i.kt)("h3",{id:"purchase-and-register-domain-through-route53-optional"},"Purchase and register domain through Route53 (optional)"),(0,i.kt)("p",null,"If you do not have a domain for your application already, it's easiest to register it through Route53.\nGo to Route53->Domains->Registered domains, then click the 'Register Domain' button, and follow the\nworkflow to register a domain name."),(0,i.kt)("h3",{id:"create-route-53-hosted-zone"},"Create Route 53 Hosted Zone"),(0,i.kt)("p",null,"In the AWS web client, go to Route 53. Make a hosted zone for the domain you plan to use for\nyour setup of Ethereal Engine. You'll be coming back here later to create DNS records."),(0,i.kt)("p",null,"Open the Hosted zone, then click on 'Hosted zone details' to see more information. The value 'Hosted zone id'\nis used in the dev/prod.values.yaml file for 'ROUTE53_HOSTED_ZONE_ID'"),(0,i.kt)("h4",{id:"point-external-registrar-subdomains-to-use-route53-nameservers-only-if-your-domain-is-registered-outside-route53"},"Point external registrar subdomains to use Route53 Nameservers (only if your domain is registered outside Route53)"),(0,i.kt)("p",null,"If you already have a domain registered with another registrar service, you'll need to add some DNS records\nin there to point the specific subdomains you'll be using to AWS' nameservers."),(0,i.kt)("p",null,"First, go to Route53->Hosted Zones and open the domain you'll be using by clicking on the domain name (or\nhighlighting the row and clicking the 'View details' button). There should be two records under Records.\nLook for the one of type 'NS'; under 'Value/Route traffic to', there should be four lines that all start\nwith 'ns-'. These will be used shortly."),(0,i.kt)("p",null,"Go to your external registrar and go to the DNS records page. For each subdomain that will be in use, you\nneed to add four records of type 'NS'. The Name wil be the subdomain, and the Nameserver will be one of\nthe four lines under the 'NS'. You need a record for each of the four lines."),(0,i.kt)("p",null,"If you're setting up multiple deployments, e.g. both a dev and prod deployment, you'll need a set of four\nNS records for each subdomain that those deployments will be behind."),(0,i.kt)("h3",{id:"create-certificates-with-acm"},"Create certificates with ACM"),(0,i.kt)("p",null,"Go to Amazon Certificate Manager. If there are no certs in that region, click on Get Started under Provision Certificates,\notherwise click on Request a Certificate."),(0,i.kt)("p",null,"You should select Request a Public Certificate, then select Request a Certificate. The next page\nshould be headed Add Domain Names. You should add both the top-level domain, such as ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine.org"),",\nas well as a wildcard for all subdomains e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"*.etherealengine.org"),", then click Next."),(0,i.kt)("p",null,"Choose DNS Validation on the next page and click Next. You can skip adding tags and just click Review,\nthen Confirm on the final page."),(0,i.kt)("p",null,"You should be sent to a page headed Validation. Click on the arrow next to each domain to open more\noptions. Click on the button Create Record in Route 53 to open a confirmation modal, and in that modal\nclick Create."),(0,i.kt)("p",null,"As it indicates, it can take up to 30 minutes for these domains to be validated. If you click on Complete\nafter triggering the record creation for each of them, you should be sent back to the Certificates page.\nOpening the cert you just made will show the validation status of each domain."),(0,i.kt)("p",null,"If you open the details of this certificate, there should be a field 'ARN' with a value that looks\nsomething like ",(0,i.kt)("inlineCode",{parentName:"p"},"arn:aws:acm:<region>:<AWS account ID>:certificate/<a UUID>"),". Take note of this for later,\nwhen you go to install ingress-nginx."),(0,i.kt)("h4",{id:"if-you-are-serving-client-files-from-client-or-api-pods"},"If you are serving client files from client or API pods"),(0,i.kt)("p",null,"You should follow the above instructions to make a second certificate for ",(0,i.kt)("inlineCode",{parentName:"p"},"resources.<domain>"),".\nNote that this certificate MUST be made in us-east-1, regardless of which region everything else is\nset up in; as of this writing, CloudFront can only use certificates in us-east-1."),(0,i.kt)("h4",{id:"if-you-are-serving-client-files-from-the-storage-provider"},"If you are serving client files from the Storage Provider"),(0,i.kt)("p",null,"You should follow the above instructions to make a second certificate for ",(0,i.kt)("inlineCode",{parentName:"p"},"<RELEASE_NAME>.<domain>"),".\nNote that this certificate MUST be made in us-east-1, regardless of which region everything else is\nset up in; as of this writing, CloudFront can only use certificates in us-east-1."),(0,i.kt)("h2",{id:"install-agones-ingress-nginx-and-a-copy-of-redis-for-each-deployment"},"Install Agones, ingress-nginx, and a copy of redis for each deployment"),(0,i.kt)("p",null,"Now that the cluster is up and running, we can install everything onto it.\nWhen you created the cluster with eksctl, it should have created a context pointing to\nit in kubectl. Run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all of the contexts it knows about;\nthe one with a star next to it should be named ",(0,i.kt)("inlineCode",{parentName:"p"},"<your_AWS_username>@<cluster_name>"),".\nIf that isn't present, you'll have to edit the configuration to make the appropriate context."),(0,i.kt)("p",null,"You next need to add the Agones, ingress-nginx, and redis Helm charts to helm by running\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add agones https://agones.dev/chart/stable"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add redis https://charts.bitnami.com/bitnami"),".\nYou should also at this time add Ethereal Engine's repo via ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add etherealengine https://helm.etherealengine.org"),"."),(0,i.kt)("p",null,"If you ever suspect that a chart is out-of-date, run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo update")," to update all of them to the latest."),(0,i.kt)("h3",{id:"install-agones"},"Install Agones"),(0,i.kt)("p",null,"From the top level of this repo, run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones"),".\nThis says to install a service called 'agones' from the 'agones' package in the 'agones' chart, and to configure it with\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," that can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,i.kt)("h3",{id:"install-redis-for-each-deployment"},"Install redis for each deployment"),(0,i.kt)("p",null,"Each deployment of Ethereal Engine uses a redis cluster for coordinating the 'feathers-sync' library.\nEach redis deployment needs to be named the same as the deployment that will use it; for an\nEthereal Engine deployment named 'dev', the corresponding redis deployment would need to be named\n'dev-redis'."),(0,i.kt)("p",null,"Run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/redis-values.yaml> <RELEASE_NAME>-redis redis/redis")," to install, e.g.\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/redis-values.yaml> dev-redis redis/redis"),"."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/redis-values.yaml"},"redis-values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("p",null,"If you named the redis nodegroup something other than 'ng-redis-1', you'll have to alter the value in\n",(0,i.kt)("inlineCode",{parentName:"p"},"redis-values.yaml")," in two places to your redis nodegroup name.\nIf you didn't create a nodegroup just for redis, you must omit the ",(0,i.kt)("inlineCode",{parentName:"p"},"-f </path/to/redis-values.yaml>"),",\nas that config makes redis pods run on a specific nodegroup."),(0,i.kt)("h4",{id:"installing-redis-as-part-of-ethereal-engine-chart-not-recommended-for-production"},"Installing redis as part of Ethereal Engine chart (not recommended for production)"),(0,i.kt)("p",null,"Redis can be installed as part of the Ethereal Engine chart so long as the config file for the Ethereal Engine installation has 'redis.enabled' set to true.\nIn that case, you should skip the above step of installing redis separately. This is not recommended for production\nenvironments, though, since upgrades to an Ethereal Engine installation will usually reboot the redis servers,\nleading all of the instanceservers to crash due to their redis connections being severed."),(0,i.kt)("p",null,"This breaks Agones' normal behavior of keeping Allocated instanceservers running until every user has left and slowly replacing\nold Ready instanceservers with new ones, maintaining an active pool of instanceservers at all times. You will encounter a period\nof time where there are no active instanceservers at all, which is not recommended, and all instanceservers in use\nwill immediately go down."),(0,i.kt)("h3",{id:"install-ingress-nginx"},"Install ingress-nginx"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"This step cannot finish until the associated ACM Certificate is fully validated"),"\nOpen local version of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/nginx-ingress-aws-values.yml"},"nginx-ingress-aws-values.yml")," file. Take note of the line\n",(0,i.kt)("inlineCode",{parentName:"p"},'service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "<ACM Certificate ARN for SSL>"'),"\nReplace the bit in angle brackets, including the angle brackets, with the ARN of the certificate\nyou made for the top-level domain and all wildcarded subdomains, e.g.\n",(0,i.kt)("inlineCode",{parentName:"p"},'service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-1:103947711118:certificate/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"')),(0,i.kt)("p",null,"Do not commit this file with the ARN inserted; once you've completed this step, revert the file back\nto the state it was committed in."),(0,i.kt)("p",null,"From the top level of this repo, run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/nginx-ingress-aws-values.yml> nginx ingress-nginx/ingress-nginx"),"\nThis says to install a service called 'nginx' from the 'ingress-nginx' package in the 'ingress-nginx' chart, and to configure it with\na file found at ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/nginx-ingress-aws-values.yml"},"nginx-ingress-aws-values.yml"),"."),(0,i.kt)("h2",{id:"set-up-simple-email-service-optional"},"Set up Simple Email Service (optional)"),(0,i.kt)("p",null,"If you want to enable email magiclink login, you will need to set up Simple Email Service (SES)."),(0,i.kt)("p",null,"In the AWS web client, go to SES -> Configuration -> Verified Identities. Click Create Identity, then under 'Identity type'\nselect 'Domain'. Enter the top-level domain under the 'Domain' field. Finally, click the 'Create identity' button."),(0,i.kt)("h3",{id:"create-smtp-credentials"},"Create SMTP credentials"),(0,i.kt)("p",null,"You need to create SMTP credentials in order to authorize SES. These will show up as an IAM user,\nbut you must go through an SES-specific process to get valid credentials; just creating an IAM user\nwith SESFullAccess will not work."),(0,i.kt)("p",null,"Go to an SES page and select 'SMTP Settings', then click the button 'Create SMTP Credentials'.\nYou can leave the default IAM User Name as-is; click the Create button. You should be taken to a screen\nsays a user has been created successfully. Click on 'Show User SMTP Security Credentials'."),(0,i.kt)("p",null,"You will see a Username and Password. These credentials will go into the Helm config file, under\nAWS_SMTP_USER and AWS_SMTP_PASS, respectively. You must also fill in the region that you've created these credentials\nin, replacing <SES_REGION> in api.extraEnv.SMTP_HOST."),(0,i.kt)("h3",{id:"move-ses-out-of-sandbox"},"Move SES out of Sandbox"),(0,i.kt)("p",null,"By default, SES domains are in Sandbox mode, where they can only send emails to verified email addresses.\nTo request that the domain be moved out of Sandbox mode, go to SES->Email Sending->Sending Statistics.\nClick on the button 'Edit your account details' to open the modal. Set 'Enable Production Access' to Yes,\nleave Mail type on 'Transactional', then fill in the Website URL, add a Use case description (basically\njust assure them that this is for account login only, not anything else), click the checkbox to agree\nto their TOD, and click the button 'Submit for review'."),(0,i.kt)("p",null,"It may take up to a few days for them to take action. If the request is rejected, address their concerns.\nOnce you have been approved, email login should work for any email address."),(0,i.kt)("h4",{id:"verifying-test-emails"},"Verifying test emails"),(0,i.kt)("p",null,"Before you have production use for your SES domain, in order to log in you'll have to verify specific email\naddresses with SES. Go to SES->Identity Management->Email Addresses. Click on the button 'Verify a New Email\nAddress'. Enter the address you want to test with, then click 'Verify This Email Address'. You should soon\nreceive an email with a link to verify it (it may go to your Spam folder). Once you've followed the link,\nyou can log in with that address."),(0,i.kt)("h2",{id:"set-up-simple-notification-service-optional"},"Set up Simple Notification Service (optional)"),(0,i.kt)("p",null,"If you want to enable text message-based magiclink login, you will need to set up Simple Notification Service (SNS)."),(0,i.kt)("p",null,"In the AWS web client, go to SNS -> Topics and Create a new topic.\nGive it a name, and selected 'Standard' as the type, then click Create Topic."),(0,i.kt)("h2",{id:"set-up-s3-bucket-for-static-resources-and-cloudfront-distribution"},"Set up S3 bucket for static resources and Cloudfront distribution"),(0,i.kt)("p",null,"Various static files are stored in S3 behind a Cloudfront distribution. If you are serving the client files\nfrom the Storage Provider, then all client files will be stored and served from these as well."),(0,i.kt)("h3",{id:"create-s3-bucket"},"Create S3 bucket"),(0,i.kt)("p",null,"In the AWS web client, go to S3 -> Buckets and click Create Bucket.\nName the bucket ",(0,i.kt)("inlineCode",{parentName:"p"},"<name>-static-resources"),", e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-static-resources"),", and have it be in Region us-east-1.\nUnder Object Ownership, select 'ACLs enabled', and under that select 'Object Writer'.\nUnder Block Public Access Settings For The Bucket, uncheck the checkbox Block ",(0,i.kt)("em",{parentName:"p"},"all")," Public Access;\nyou need the bucket to be publicly accessible.\nCheck the box that pops up confirming that you know the contents are public.\nAll other settings can be left to their default values; click Create Bucket."),(0,i.kt)("p",null,"Open the bucket's settings and go the Permissions tab. Midway down is 'Access control list'. Edit that, and\nCheck the boxes for Objects:List and Bucket ACL:Read for 'Everyone (public access)'. Click the box with the\nwarning label that appears that says \"I understand the effects of these changes on my objects and buckets\",\nthen click Save Changes.\nAt the bottom of the Permissions tab is a Cross-origin Resource Sharing (CORS) box.\nIt should have the following settings; if not, click Edit and copy this in:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'[\n {\n "AllowedHeaders": [],\n "AllowedMethods": [\n "HEAD",\n "GET",\n "POST"\n ],\n "AllowedOrigins": [\n "*"\n ],\n "ExposeHeaders": []\n }\n]\n')),(0,i.kt)("h3",{id:"create-cloudfront-distribution"},"Create Cloudfront distribution"),(0,i.kt)("p",null,"In the AWS web client, go to Cloudfront -> Distributions and click on Create Distribution.\nUnder 'Web', click on Get Started."),(0,i.kt)("p",null,"Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin"),", click on the text box under ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin domain"),", and select the name of the S3 bucket you just made.\nThe ",(0,i.kt)("inlineCode",{parentName:"p"},"Name")," field should be automatically populated, and should be left as whatever that value is."),(0,i.kt)("p",null,"Several fields in ",(0,i.kt)("inlineCode",{parentName:"p"},"Default cache behavior")," will be changed."),(0,i.kt)("p",null,"Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Viewer -> Viewer protocol policy"),", select 'Redirect HTTP to HTTPS'\nUnder ",(0,i.kt)("inlineCode",{parentName:"p"},"Viewer -> Allowed HTTP methods"),", select 'GET, HEAD, OPTIONS', and check ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache HTTP methods -> OPTIONS"),"."),(0,i.kt)("p",null,"In ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache key and origin requests"),", leave it on ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy and origin request policy"),".\nIf this option is not available, see the below subsection for ",(0,i.kt)("inlineCode",{parentName:"p"},"Legacy cache settings")),(0,i.kt)("p",null,"For ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy"),", you will need to make a new policy, which is easily done by clicking the link ",(0,i.kt)("inlineCode",{parentName:"p"},"Create policy"),"\nunderneath the selector; this will open a new tab. Name this policy anything you want, e.g. 'Cached-on-headers',\nthen under ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache key settings"),", click on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Headers")," selector and select 'Include the following headers'. A new\nselector should appear under that titled ",(0,i.kt)("inlineCode",{parentName:"p"},"Add header"),". Click the selector, and check 'Origin',\n'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away from the menu. Click the 'Create'\nbutton to create the new policy."),(0,i.kt)("p",null,"Once the policy has been created, go back to the tab that you were creating the CloudFront distribution in.\nClick the refresh button to the right of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy")," selector to fetch your new policy, then click the selector,\nand your new policy should appear in the selector at the bottom of the list under the header 'Custom'. Select it."),(0,i.kt)("p",null,"For ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin request policy"),", select the option 'CORS-S3Origin'."),(0,i.kt)("p",null,"You should also make a custom response header policy so that files are served with the ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin-Agent-Cluster"),"\nheader, which will tell most browsers to isolate resources for same-site cross-origin requests. To do that,\nyou will need to make a custom response header policy. Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Response headers policy"),", select ",(0,i.kt)("inlineCode",{parentName:"p"},"Create Policy"),".\nThis will open a separate tab. Name this something like ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin-Agent-Cluster"),", then under ",(0,i.kt)("inlineCode",{parentName:"p"},"Custom headers"),",\nclick ",(0,i.kt)("inlineCode",{parentName:"p"},"Add header"),". For name, enter ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin-Agent-Cluster"),", and for ",(0,i.kt)("inlineCode",{parentName:"p"},"Value"),", enter ",(0,i.kt)("inlineCode",{parentName:"p"},"?1"),". Then click the ",(0,i.kt)("inlineCode",{parentName:"p"},"Create"),"\nbutton at the bottom."),(0,i.kt)("p",null,"Go back to the tab where you were creating the Cloudfront distribution. Click the refresh button to the right of\nthe ",(0,i.kt)("inlineCode",{parentName:"p"},"Response headers policy")," selector to fetch the new policy, then click the selector, and your new policy should\nappear in the selector at the bottom of the list under the header ",(0,i.kt)("inlineCode",{parentName:"p"},"Custom"),". Select it."),(0,i.kt)("p",null,"Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Settings"),", you can change ",(0,i.kt)("inlineCode",{parentName:"p"},"Price class")," to 'Use Only North America and Europe' to save some money.\nFor Alternate Domain Names, click 'Add item', then in the text box that appears, enter 'resources.",(0,i.kt)("inlineCode",{parentName:"p"},"<domain>"),"', e.g.\n",(0,i.kt)("inlineCode",{parentName:"p"},"resources.etherealengine.org"),", or '<RELEASE_NAME>.",(0,i.kt)("inlineCode",{parentName:"p"},"<domain>"),"', e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"dev.etherealengine.org"),", depending on\nwhether you are serving the client files from client/API pods or the Storage Provider, respectively.\nUnder ",(0,i.kt)("inlineCode",{parentName:"p"},"Custom SSL Certificate"),", click on the selector that says 'Choose certificate', then select the\n'resources.",(0,i.kt)("inlineCode",{parentName:"p"},"<domain>"),"'/'",(0,i.kt)("inlineCode",{parentName:"p"},"<RELEASE_NAME>.<domain>"),"' certificate you made earlier. If you are serving the client\nfiles from the Storage Provider, under ",(0,i.kt)("inlineCode",{parentName:"p"},"Default root object"),", enter ",(0,i.kt)("inlineCode",{parentName:"p"},"client/index.html"),"; if you are serving\nthe client files from client/API pods, leave this blank."),(0,i.kt)("p",null,"Everything else can be left at the default values, click Create Distribution."),(0,i.kt)("h4",{id:"legacy-cache-settings"},"Legacy cache settings"),(0,i.kt)("p",null,"If for some reason ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy and origin request policy")," is not available for you, and you have to use\n",(0,i.kt)("inlineCode",{parentName:"p"},"Legacy cache settings"),", the under ",(0,i.kt)("inlineCode",{parentName:"p"},"Headers"),", select 'Include the following headers'. Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Add header")," that appears,\nclick on the selector titled 'Select headers', and in the menu that opens, check 'Host', 'Origin',\n'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away."),(0,i.kt)("h2",{id:"set-up-dns-records"},"Set up DNS records"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"The Nginx Load Balancer must be fully set up and running before this step can be completed")),(0,i.kt)("p",null,"In the AWS web client, go to Route 53, then go into the Hosted Zone you made earlier.\nClick on Create Record. If it starts you under Quick Create Record, click the link\n'Switch to Wizard'; it's not necessary, but the wizard is handy."),(0,i.kt)("p",null,"Under Routing Policy, leave it on Simple Routing and click Next. Then click Define Simple Record."),(0,i.kt)("p",null,"The first record should be for the top-level domain, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine.org"),", so leave the Record Name\ntext field blank. Under Value/Route Traffic To, click on the dropdown and select\nAlias to Network Load Balancer. Select the region that your cluster is in.\nWhere it says Choose Load Balancer, click the dropdown, and select the NLB that was created.\nLeave the Record Type as 'A - Route traffic to an IPv4 address and some AWS resources', then click\nDefine Simple Record."),(0,i.kt)("p",null,"You can keep clicking Define Simple Record to make more records in one batch. When you're\ndone, click Create Records."),(0,i.kt)("p",null,"You should make the following 'A' records to the loadbalancer, substituting your domain for 'etherealengine.org':"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"*.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"@.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"api-dev.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"api.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"dev.etherealengine.org -- Only if serving client files from client/API pods"),(0,i.kt)("li",{parentName:"ul"},"instanceserver.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"instanceserver-dev.etherealengine.org")),(0,i.kt)("p",null,"You also need to make an 'A' record pointing 'resources.etherealengine.org' or '<RELEASE_NAME>.etheralengine.org' to the\nCloudFront distribution you made earlier.\nInstead of 'Alias to Network Load Balancer', select 'Alias to Cloudfront distribution', then click the text box that appears\nthat says 'Choose distribution'. A selector should appear with the subdomain you're routing as well as the Cloudfront\ndistribution's domain name, which you should click on. Then click Define simple record."),(0,i.kt)("h2",{id:"create-github-fork-of-ethereal-engine-repository"},"Create GitHub fork of Ethereal Engine repository."),(0,i.kt)("p",null,"The Ethereal Engine codebase is most easily deployed by forking it and configuring some Secrets so that the included GitHub\nActions can run the deployment for you. You can run all of the commands that the ",(0,i.kt)("inlineCode",{parentName:"p"},"<dev/prod>"),"-deploy action runs manually\nif you so choose, and in that case, you don't need to fork the GH repo."),(0,i.kt)("p",null,"Go to ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine"},"https://github.com/etherealengine/etherealengine"),". In the upper right-hand corner, there's a button 'Fork'. Click that,\nthen click the account/organization you wish to fork it to. You should be taken to your fork in a short time."),(0,i.kt)("p",null,"You'll need to set several Secrets (runtime variables) for GitHub Actions. By default GitHub Actions should be fully\nenabled, but you can double-check by going to Settings->Actions. Allow All Actions should be selected under Actions\nPermissions."),(0,i.kt)("p",null,"Next click on Secrets under Settings. There should be none by default. Click on New Repository Secret near the top of\nthis page to make a new one. You will need to make several Secrets with the following Names and Values:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"EKS_AWS_ACCESS_KEY -> The public Key of the EKSUser IAM user"),(0,i.kt)("li",{parentName:"ul"},"AWS_REGION -> The region of your ECR repos and EKS cluster"),(0,i.kt)("li",{parentName:"ul"},"EKS_AWS_SECRET -> The secret key of the EKSUser IAM user"),(0,i.kt)("li",{parentName:"ul"},"CLUSTER_NAME -> The name of the EKS cluster"),(0,i.kt)("li",{parentName:"ul"},"DEPLOYMENTS_ENABLED -> Set to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")),(0,i.kt)("li",{parentName:"ul"},"DEV_REPO_NAME -> The base name of the dev ECR repository, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"etherealengine-dev")," (all references to the builder and service repos will append ",(0,i.kt)("inlineCode",{parentName:"li"},"-builder"),"/",(0,i.kt)("inlineCode",{parentName:"li"},"-<service>")," to this value)"),(0,i.kt)("li",{parentName:"ul"},"DOCKER_LABEL -> This can be almost anything, but you can use ",(0,i.kt)("inlineCode",{parentName:"li"},"lagunalabs/etherealengine")),(0,i.kt)("li",{parentName:"ul"},"ECR_URL -> The root ECR_URL for your repos, i.e. everything before the ",(0,i.kt)("inlineCode",{parentName:"li"},"/etherealengine-dev-builder"),", e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"11111111111.dkr.ecr.us-west-1.amazonaws.com")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"public.ecr.aws/a1b2c3d4")),(0,i.kt)("li",{parentName:"ul"},"PRIVATE_ECR -> Set this to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," if your ECR repos are private, if they're public you don't need to set this at all")),(0,i.kt)("p",null,"If you go to the Actions Tab, you might see a few workflow runs with green checkmarks. If so, you'll be re-running the\n",(0,i.kt)("inlineCode",{parentName:"p"},"dev-deploy")," workflow shortly; its initial run just ran a check to see if it should do a deployment based on\n",(0,i.kt)("inlineCode",{parentName:"p"},"DEPLOYMENTS_ENABLED"),", and since that wasn't set to true, it didn't do anything else. Now that that's set to true,\nre-running it will trigger a deployment."),(0,i.kt)("p",null,"If you're asked to enable actions when going to the tab, and there are no runs listed after enabling actions, then you'll have to\ntrigger the workflow by pushing new code to the dev branch."),(0,i.kt)("h2",{id:"grant-eksuser-access-to-cluster"},"Grant EKSUser access to cluster"),(0,i.kt)("p",null,"By default, only the IAM user who set up an EKS cluster may access it.\nIn order to let other users access the cluster, you must apply an aws-auth configmap to the cluster\ngranting access to specific IAM users. A template of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/aws-auth-template.yml"},"aws-auth-template.yml")," file can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,i.kt)("p",null,"You'll need to provide a few values for this file. To find ",(0,i.kt)("inlineCode",{parentName:"p"},"<rolearn>"),", in AWS go to EKS->Clusters->\n",(0,i.kt)("inlineCode",{parentName:"p"},"<your cluster>"),"->Compute->Select a nodegroup. In the details should be 'Node IAM Role ARN'; copy this\nand replace ",(0,i.kt)("inlineCode",{parentName:"p"},"<rolearn>")," in the aws-auth file. ",(0,i.kt)("inlineCode",{parentName:"p"},"<account_id>")," is the ID of your AWS account; in the upper\nright corner of the AWS client should be ",(0,i.kt)("inlineCode",{parentName:"p"},"<your_username>@<abcd-1234-efgh>"),". The 12-character string\nafter the @ is the account ID. Make sure to remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"-"),"'s from the account ID when pasting it in.\n",(0,i.kt)("inlineCode",{parentName:"p"},"<IAM_username>")," is the username of the IAM user you want to give access, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"EKSUser"),"."),(0,i.kt)("p",null,"You can add multiple users by copying the ",(0,i.kt)("inlineCode",{parentName:"p"},"- groups:")," section under ",(0,i.kt)("inlineCode",{parentName:"p"},"mapUsers"),", e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," mapUsers: |\n - groups:\n - system:masters\n userarn: arn:aws:iam::abcd1234efgh:user/EKSUser\n username: EKSUser\n - groups:\n - system:masters\n userarn: arn:aws:iam::acbd1234efgh:user/FSmith\n username: FSmith\n")),(0,i.kt)("p",null,"When the aws-auth config file is filled in, just run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl apply -f path/to/aws-auth.yml"),"."),(0,i.kt)("h2",{id:"deploy-to-eks-using-helm"},"Deploy to EKS using Helm"),(0,i.kt)("p",null,"With all of the networking set up, you can finally deploy the codebase to EKS.\nThere's a couple of steps to this, which will involve deploying things with most but not all of the needed\nconfiguration values, and then letting the deployment process fill in the rest."),(0,i.kt)("h3",{id:"fill-in-helm-config-file-with-variables"},"Fill in Helm config file with variables"),(0,i.kt)("p",null,"Template Helm config files for dev and prod deployments can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs"},"configs")," <dev/prod>.template.values.yaml.\nBefore filling them in, make a copy elsewhere, call that '<dev/prod>.values.yaml', and edit that copy.\nBoth the builder and main deployments should use the same config file. When the builder seeds the database,\nit needs a number of values that only need to be configured for the other services, so all of the values\nneed to be defined in one config file."),(0,i.kt)("p",null,"There are many fields to fill in, most marked with ",(0,i.kt)("inlineCode",{parentName:"p"},"<>"),". Not all are necessary for all situations - if you're not\nusing social login, for instance, you don't need credentials for Github/Google/Facebook/etc."),(0,i.kt)("h3",{id:"configuration-variables-of-note"},"Configuration variables of note"),(0,i.kt)("p",null,"Here are some configuration variables that you'll probably need to change based on your specific setup"),(0,i.kt)("h4",{id:"apiinstanceservertaskserverextraenvauth_secret"},"<api/instanceserver/taskserver>.extraEnv.AUTH_SECRET"),(0,i.kt)("p",null,"This is a secret value that is used to sign the JWTs that authenticate users.\nYou can use any string for this value, and a randomly-generated one of sufficient length,\ni.e. 32 or more characters, will suffice. If this is changed after some users have signed\nin, their login credentials won't work any more."),(0,i.kt)("h4",{id:"apiclienttaskserveraffinitynodeaffinity"},"<api/client/taskserver>.affinity.nodeAffinity"),(0,i.kt)("p",null,"Within the sections of the config for the api, client, instanceserver, etc., is a section that looks\nsomething like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," affinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: eks.amazonaws.com/nodegroup\n operator: In\n values:\n - ng-1\n")),(0,i.kt)("p",null,"The value, ",(0,i.kt)("inlineCode",{parentName:"p"},"ng-1")," in this example, must be changed to match whatever the name of the nodegroup that\nthat service will be running on, e.g. if you create a nodegroup for the instanceservers called\n",(0,i.kt)("inlineCode",{parentName:"p"},"abcd-instanceservers-5"),", then you'd use that value under ",(0,i.kt)("inlineCode",{parentName:"p"},"values:")),(0,i.kt)("p",null,"If your EKS setup created a nodegroup for you, and you want to use that for the api, client, and\ntask servers, make sure to change the affinity value for them to whatever EKS named the\ninitial nodegroup."),(0,i.kt)("h4",{id:"builderextraenvprivate_ecr"},"builder.extraEnv.PRIVATE_ECR"),(0,i.kt)("p",null,'If you\'re using a private ECR repo, set this to "true" in the builder config file.'),(0,i.kt)("h4",{id:"everythingimagerepository"},"(everything).image.repository"),(0,i.kt)("p",null,"You'll need to replace every <repository_name> with the full ECR_URL of your non-builder repos, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"abcd1234efgh.dkr.ecr.us-west-1.amazonaws.com/etherealengine-dev-api"),".\nEach service has to have the proper ",(0,i.kt)("inlineCode",{parentName:"p"},"-<service>")," suffix on it, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"-api"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"-client"),", etc."),(0,i.kt)("h4",{id:"github_client_idgithub_client_secret"},"GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET"),(0,i.kt)("p",null,"If you plan to backup Projects you create in the editor to GitHub, or install project from GitHub, it is necessary\nto set up the OAuth app that will facilitate this before the initial installation.\nSee ",(0,i.kt)("a",{parentName:"p",href:"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects"},"this document")," for\nmore information, and enter the appropriate ID/secret in these variables."),(0,i.kt)("h3",{id:"run-helm-install"},"Run Helm install"),(0,i.kt)("p",null,"Run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME>-builder etherealengine/etherealengine-builder"),"\nand then run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME> etherealengine/etherealengine")),(0,i.kt)("p",null,"This will spin up the main and builder deployments using the Helm config file, <dev/prod>.values.yaml.\nNeither will fully work yet, since there's no valid image in the repos yet. The GitHub\nActions and builder processes will make those images and update the deployments with the tags of the images they've built\nso that they can pull down and use those images."),(0,i.kt)("h2",{id:"kick-off-github-actions"},"Kick off GitHub Actions"),(0,i.kt)("p",null,"In GitHub, if you go to back to the Actions tab, you should see a ",(0,i.kt)("inlineCode",{parentName:"p"},"dev-deploy")," action. Click on it, and you should see\na page showing its status, which should be all green checkmarks or indicators that things didn't run. In the upper\nright, click ",(0,i.kt)("inlineCode",{parentName:"p"},"Re-run all jobs"),". This will start it again, and now that ",(0,i.kt)("inlineCode",{parentName:"p"},"DEPLOYMENTS_ENABLED")," is set to true, it should\nattempt to build and deploy the builder."),(0,i.kt)("p",null,"(If actions were disabled at first, you'll have to merge additional code into the dev branch to get it to start the dev-deploy process)"),(0,i.kt)("h3",{id:"overview-of-the-build-process"},"Overview of the build process"),(0,i.kt)("p",null,"The full build and deployment process works like this:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"GitHub Actions builds just enough of the Ethereal Engine monorepo to fetch any installed Ethereal Engine projects."),(0,i.kt)("li",{parentName:"ol"},"GitHub Actions pushes this builder Docker image to the repo ",(0,i.kt)("inlineCode",{parentName:"li"},"etherealengine-<release>-builder")," in ECR"),(0,i.kt)("li",{parentName:"ol"},"GitHub Actions updates the builder deployment to point to the builder image it just created."),(0,i.kt)("li",{parentName:"ol"},"The builder deployment spins up the builder Docker image on its single node"),(0,i.kt)("li",{parentName:"ol"},"The builder connects to the deployment's database and checks if there is a table ",(0,i.kt)("inlineCode",{parentName:"li"},"user"),". This is a proxy\nfor the database being seeded; if it does not exist, it seeds the database with the basic Ethereal Engine schema,\nseeds the default project into the database and storage provider, and seeds various types."),(0,i.kt)("li",{parentName:"ol"},"The builder downloads any Ethereal Engine projects that the deployment has added."),(0,i.kt)("li",{parentName:"ol"},"The builder builds the Docker image for each service concurrently using these projects, building them into the client files as well as copying them so that the api and instanceservers have access to them.\nIf serving client files from the Storage Provider, the client files will be pushed to S3"),(0,i.kt)("li",{parentName:"ol"},"The builder pushes these final Docker images to the repos ",(0,i.kt)("inlineCode",{parentName:"li"},"etherealengine-<release>-<service>")," in ECR (not the client image if serving client files from the Storage Provider)"),(0,i.kt)("li",{parentName:"ol"},"The builder caches all of the layers of each Docker file in S3 for faster build times on subsequent builds"),(0,i.kt)("li",{parentName:"ol"},"The builder updates the main deployment to point to the final images it just created."),(0,i.kt)("li",{parentName:"ol"},"The main deployment spins up the final Docker images for the api, client (optional), instanceserver and taskserver services.")),(0,i.kt)("h2",{id:"install-elastic-search-and-kibana-using-helm-for-server-logs"},"Install Elastic Search and Kibana using Helm for Server Logs"),(0,i.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,i.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,i.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart: "),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,i.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,i.kt)("p",null,"Now check if the cluster members are up: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,i.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,i.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana"),"\nCheck if all the pods are ready: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,i.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"http://localhost:5601 "),"in your browser"),(0,i.kt)("p",null,"In order to connect logger with elasticsearch, update config file(values.yml) for Xr env ",(0,i.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,i.kt)("h3",{id:"upgrading-an-existing-helm-deployment"},"Upgrading an existing Helm deployment"),(0,i.kt)("p",null,"One of the features of Helm is being able to easily upgrade deployments with new values. The command to\ndo this is very similar to the install command:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/*.values.yaml> --set api.image.tag=<latest_github_commit_SHA>,client.image.tag=<latest_github_commit_SHA>,instanceserver.image.tag=<latest_github_commit_SHA> <RELEASE_NAME> etherealengine/etherealengine")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"--reuse-values")," says to carry over all configuration values from the previous deployment. This is most important\nfor tags, since they're usually set inline with the ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install/upgrade")," command, not a Helm config.\nUsing ",(0,i.kt)("inlineCode",{parentName:"p"},"-f <config_file>")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"--set <variables>")," after it will apply any changes on top of the\ncarryover values."),(0,i.kt)("p",null,"If you're not deploying a new build of the codebase, you can skip the entirety of the ",(0,i.kt)("inlineCode",{parentName:"p"},"--set *.image.tag=<SHA>"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6807199d.e53be443.js b/assets/js/6807199d.e53be443.js new file mode 100644 index 000000000000..66297fea1221 --- /dev/null +++ b/assets/js/6807199d.e53be443.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[301],{3905:(e,r,t)=>{t.d(r,{Zo:()=>p,kt:()=>m});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function i(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),l=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):c(c({},r),e)),t},p=function(e){var r=l(e.components);return n.createElement(s.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(t),f=a,m=u["".concat(s,".").concat(f)]||u[f]||d[f]||o;return t?n.createElement(m,c(c({ref:r},p),{},{components:t})):n.createElement(m,c({ref:r},p))}));function m(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var o=t.length,c=new Array(o);c[0]=f;var i={};for(var s in r)hasOwnProperty.call(r,s)&&(i[s]=r[s]);i.originalType=e,i[u]="string"==typeof e?e:a,c[1]=i;for(var l=2;l<o;l++)c[l]=t[l];return n.createElement.apply(null,c)}return n.createElement.apply(null,t)}f.displayName="MDXCreateElement"},6364:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>s,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>l});var n=t(7462),a=(t(7294),t(3905));const o={},c=void 0,i={unversionedId:"creator/avatars/readme",id:"creator/avatars/readme",title:"readme",description:"",source:"@site/docs/2_creator/7_avatars/readme.md",sourceDirName:"2_creator/7_avatars",slug:"/creator/avatars/",permalink:"/etherealengine-docs/docs/creator/avatars/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/7_avatars/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Debugging Deployed Instanceservers (and other Kubernetes pods)",permalink:"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers"},next:{title:"Ethereal for Guests",permalink:"/etherealengine-docs/docs/guest/"}},s={},l=[],p={toc:l},u="wrapper";function d(e){let{components:r,...t}=e;return(0,a.kt)(u,(0,n.Z)({},p,t,{components:r,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6945.326f966e.js b/assets/js/6945.326f966e.js new file mode 100644 index 000000000000..2a4b1f6ba818 --- /dev/null +++ b/assets/js/6945.326f966e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6945],{6945:(e,s,n)=>{n.r(s)}}]); \ No newline at end of file diff --git a/assets/js/75750052.ed83fca3.js b/assets/js/75750052.ed83fca3.js new file mode 100644 index 000000000000..8116c949dc56 --- /dev/null +++ b/assets/js/75750052.ed83fca3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[532],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>b});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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var g=r.createContext({}),s=function(e){var t=r.useContext(g),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=s(e.components);return r.createElement(g.Provider,{value:t},e.children)},u="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,i=e.mdxType,o=e.originalType,g=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=s(n),p=i,b=u["".concat(g,".").concat(p)]||u[p]||d[p]||o;return n?r.createElement(b,a(a({ref:t},l),{},{components:n})):r.createElement(b,a({ref:t},l))}));function b(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=p;var c={};for(var g in t)hasOwnProperty.call(t,g)&&(c[g]=t[g]);c.originalType=e,c[u]="string"==typeof e?e:i,a[1]=c;for(var s=2;s<o;s++)a[s]=n[s];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},2510:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>g,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const o={hide_table_of_contents:!0},a="Debugging",c={unversionedId:"creator/testing/debugging",id:"creator/testing/debugging",title:"Debugging",description:"This section covers different techniques for debugging the source code.",source:"@site/docs/2_creator/6_testing/4_debugging.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/debugging",permalink:"/etherealengine-docs/docs/creator/testing/debugging",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/4_debugging.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Writing Good Tests",permalink:"/etherealengine-docs/docs/creator/testing/test_driven_development"},next:{title:"Debugging Engine in WSL on Phone/Headset",permalink:"/etherealengine-docs/docs/creator/testing/debugging_device_wsl"}},g={},s=[{value:"Basic Debugging",id:"basic-debugging",level:2}],l={toc:s},u="wrapper";function d(e){let{components:t,...o}=e;return(0,i.kt)(u,(0,r.Z)({},l,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"debugging"},"Debugging"),(0,i.kt)("p",null,"This section covers different techniques for debugging the source code."),(0,i.kt)("h2",{id:"basic-debugging"},"Basic Debugging"),(0,i.kt)("p",null,"This config can be used to debug instance server & backend server code. Navigate to 'Run & Debug' tab of vscode."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Add a breakpoint to desired line of code.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Select 'Debug Dev' from debug config dropdown.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Hit the run/play button to start debugging.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Breakpoint will be hit as the code executes that line of code."))),(0,i.kt)("p",null,"Below image further elaborates this."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Basic Debug Image",src:n(8542).Z,width:"1919",height:"960"})))}d.isMDXComponent=!0},8542:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png"}}]); \ No newline at end of file diff --git a/assets/js/82399a21.a358d094.js b/assets/js/82399a21.a358d094.js new file mode 100644 index 000000000000..bbdeb7d2b4b5 --- /dev/null +++ b/assets/js/82399a21.a358d094.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1473],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>g});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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),c=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(o.Provider,{value:t},e.children)},u="mdxType",h={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,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,g=u["".concat(o,".").concat(m)]||u[m]||h[m]||i;return n?a.createElement(g,l(l({ref:t},p),{},{components:n})):a.createElement(g,l({ref:t},p))}));function g(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 s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[u]="string"==typeof e?e:r,l[1]=s;for(var c=2;c<i;c++)l[c]=n[c];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8993:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const i={hide_table_of_contents:!0},l="Unreal Bridge",s={unversionedId:"creator/tutorials/ethereal_engine/unreal_bridge",id:"creator/tutorials/ethereal_engine/unreal_bridge",title:"Unreal Bridge",description:"https://github.com/etherealengine/XRE-Bridge-Unreal",source:"@site/docs/2_creator/5_tutorials/1_ethereal_engine/02_unreal_bridge.md",sourceDirName:"2_creator/5_tutorials/1_ethereal_engine",slug:"/creator/tutorials/ethereal_engine/unreal_bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/1_ethereal_engine/02_unreal_bridge.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Unity Bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge"},next:{title:"Testing",permalink:"/etherealengine-docs/docs/creator/testing/"}},o={},c=[{value:"Setup",id:"setup",level:2},{value:"Containerization details",id:"containerization-details",level:3},{value:"Configuring gameserver",id:"configuring-gameserver",level:2},{value:"VaREST and wrapping the Ethereal Engine Web API",id:"varest-and-wrapping-the-ethereal-engine-web-api",level:2},{value:"Open Match Endpoint Reference",id:"open-match-endpoint-reference",level:4}],p={toc:c},u="wrapper";function h(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"unreal-bridge"},"Unreal Bridge"),(0,r.kt)("iframe",{width:"100%",height:"600",src:"https://www.youtube.com/embed/GbOpJRxkux8?&theme=dark&rel=0",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen",allowfullscreen:!0}),(0,r.kt)("h1",{id:"ethereal-engine-bridge---unreal"},"Ethereal Engine Bridge - Unreal"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/XRE-Bridge-Unreal"},"https://github.com/etherealengine/XRE-Bridge-Unreal")),(0,r.kt)("p",null,"Unreal SDK Ethereal Engine Alpha"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"User Management API"),(0,r.kt)("li",{parentName:"ul"},"Server Party Matchmaker"),(0,r.kt)("li",{parentName:"ul"},"Unreal Game Server Lifecycle System"),(0,r.kt)("li",{parentName:"ul"},"Unreal Blueprints Ethereal Engine SDK")),(0,r.kt)("p",null,"CMS and marketplace services coming soon"),(0,r.kt)("p",null,"EXAMPLE ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example"},"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example")),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172299848-3e1c6a5f-ecd2-4562-a894-0d8b55e5b9e5.png",alt:"Screenshot 2022-06-06 193750"})),(0,r.kt)("h2",{id:"setup"},"Setup"),(0,r.kt)("p",null,"This guide assumes you have a working linux dedicated server build of you game."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/HowTo/DedicatedServers/"},"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/HowTo/DedicatedServers/")),(0,r.kt)("li",{parentName:"ul"},"old guides ",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://michaeljcole.github.io/wiki.unrealengine.com/Dedicated_Server_Guide_(Windows_&_Linux)/"},"https://michaeljcole.github.io/wiki.unrealengine.com/Dedicated_Server_Guide_(Windows_&_Linux)/")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://medium.com/swlh/building-and-hosting-an-unreal-engine-dedicated-server-with-aws-and-docker-75317780c567"},"https://medium.com/swlh/building-and-hosting-an-unreal-engine-dedicated-server-with-aws-and-docker-75317780c567"))))),(0,r.kt)("p",null,"Preinstall Requirements"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"VaRest ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/ufna/VaRest"},"https://github.com/ufna/VaRest"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536"},"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536")),(0,r.kt)("li",{parentName:"ul"},"VaREST Tuturials ",(0,r.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=B90jnsEJ6E0"},"https://www.youtube.com/watch?v=B90jnsEJ6E0")))),(0,r.kt)("li",{parentName:"ul"},"Agones SDK w/ Unreal tools ",(0,r.kt)("a",{parentName:"li",href:"https://agones.dev/site/docs/guides/client-sdks/unreal/"},"https://agones.dev/site/docs/guides/client-sdks/unreal/"))),(0,r.kt)("h3",{id:"containerization-details"},"Containerization details"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/dedicated-servers"},"https://unrealcontainers.com/docs/use-cases/dedicated-servers")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/linux-installed-builds"},"https://unrealcontainers.com/docs/use-cases/linux-installed-builds")),(0,r.kt)("li",{parentName:"ul"},"killer advanced use ",(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/pixel-streaming"},"https://unrealcontainers.com/docs/use-cases/pixel-streaming")),(0,r.kt)("li",{parentName:"ul"},"killer advanced use ",(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/continuous-integration"},"https://unrealcontainers.com/docs/use-cases/continuous-integration")),(0,r.kt)("li",{parentName:"ul"},"killer advanced use ",(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/linux-sandboxed-editor"},"https://unrealcontainers.com/docs/use-cases/linux-sandboxed-editor"))),(0,r.kt)("h2",{id:"configuring-gameserver"},"Configuring gameserver"),(0,r.kt)("p",null,"register a process with ENV VARS or Unreal executable arguments"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/CommandLineArguments/"},"https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/CommandLineArguments/")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TroveServer.exe IslandLobby.uproject /Trove/Maps/Island1?game=MyGameInfo?listen -lobbygame -server 127.0.0.1\nTroveServer.exe IsleOfDeath.uproject /Trove/Maps/IsleOfDeathStart?game=MyGameInfo?listen -stakedgame -server 127.0.0.1\n")),(0,r.kt)("h2",{id:"varest-and-wrapping-the-ethereal-engine-web-api"},"VaREST and wrapping the Ethereal Engine Web API"),(0,r.kt)("p",null,"knowledge required: Learn REST APIs, OpenAPI, Header based http auth, Verbs:Get/Post/etc, paylods, json"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172028597-08e4c4cc-973b-4e4a-924a-1f508dfb4711.png",alt:"image"})),(0,r.kt)("p",null,"Targeting support for 4.26 and 4.27"),(0,r.kt)("p",null,"Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/XRE-Bridge-Unreal/"},"https://github.com/etherealengine/XRE-Bridge-Unreal/")),(0,r.kt)("p",null,"This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine "),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://api-dev.etherealengine.com/openapi/"},"https://api-dev.etherealengine.com/openapi/")),(0,r.kt)("p",null,"This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!"),(0,r.kt)("p",null,"This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database"),(0,r.kt)("img",{width:"1189",alt:"Screen Shot 2022-06-04 at 4 25 43 PM",src:"https://user-images.githubusercontent.com/5104160/172028647-084f7aa0-d358-4b15-b6be-5788ee7d7ec4.png"}),(0,r.kt)("p",null,"Blueprints multiplayer Unreal reference"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/"},"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/")),(0,r.kt)("p",null,"All K8 control plane systems can be access via rest calls to the local network of the gameserver, the functionality of Agones can be done via adding a node in Blueprints."),(0,r.kt)("p",null,"The Ethereal Engine matchmaker service exposes the default endopints for open match."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/01-open-match-core.yaml"},"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/01-open-match-core.yaml"),"\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/07-open-match-default-evaluator.yaml"},"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/07-open-match-default-evaluator.yaml")),(0,r.kt)("p",null,"REST API local call access docs"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://open-match.dev/site/docs/guides/access/"},"https://open-match.dev/site/docs/guides/access/")),(0,r.kt)("p",null,"This is a ticketing system to be placed into a lobby group and then into a gameserver. Ethereal Engine has API call examples of this"),(0,r.kt)("p",null,"Match User Relation"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-user/match-user.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-user/match-user.class.ts")),(0,r.kt)("h4",{id:"open-match-endpoint-reference"},"Open Match Endpoint Reference"),(0,r.kt)("p",null,"Match the ticket for an assignment"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket/match-ticket.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket/match-ticket.class.ts")),(0,r.kt)("p",null,"Match Gameserver Instance Relation"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-instance/match-instance.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-instance/match-instance.class.ts")),(0,r.kt)("p",null,"Get a ticket for assignment to a gameserver instance"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket-assignment/match-ticket-assignment.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket-assignment/match-ticket-assignment.class.ts")),(0,r.kt)("p",null,"Agones Actions"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172027649-676723a1-a5d1-46f0-9406-eb2aa429cf18.png",alt:"unreal_bp_actions"})),(0,r.kt)("h1",{id:"ethereal-engine-bridge-unreal-example"},"Ethereal-Engine-Bridge-Unreal-Example"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example"},"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example")),(0,r.kt)("p",null,"Preinstall Requirements"),(0,r.kt)("p",null,"Add Plugins"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"From asset store VaRest",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/ufna/VaRest"},"https://github.com/ufna/VaRest")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536"},"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536")))),(0,r.kt)("li",{parentName:"ul"},"Add agones plugin folder - unreal or project folder",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Agones SDK w/ Unreal tools ",(0,r.kt)("a",{parentName:"li",href:"https://agones.dev/site/docs/guides/client-sdks/unreal/"},"https://agones.dev/site/docs/guides/client-sdks/unreal/"))))),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172296219-06d6d420-7fc4-4981-bf0a-35869768adcd.png",alt:"Screenshot 2022-06-06 193750"})),(0,r.kt)("p",null,"Targeting support for 4.26 and 4.27"),(0,r.kt)("p",null,"Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/XRE-Bridge-Unreal/"},"https://github.com/etherealengine/XRE-Bridge-Unreal/")),(0,r.kt)("p",null,"This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine "),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://api-dev.etherealengine.com/openapi/"},"https://api-dev.etherealengine.com/openapi/")),(0,r.kt)("p",null,"This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!"),(0,r.kt)("p",null,"This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database"),(0,r.kt)("img",{width:"1189",alt:"Screen Shot 2022-06-04 at 4 25 43 PM",src:"https://user-images.githubusercontent.com/5104160/172028647-084f7aa0-d358-4b15-b6be-5788ee7d7ec4.png"}),(0,r.kt)("p",null,"Blueprints multiplayer Unreal reference"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/"},"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/")),(0,r.kt)("p",null,"Modeled after an updated version of"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://www.unrealengine.com/marketplace/en-US/product/multiplayer-shootout"},"https://www.unrealengine.com/marketplace/en-US/product/multiplayer-shootout"),"\n",(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/Basics/Projects/UIProjectConversion/"},"https://docs.unrealengine.com/4.27/en-US/Basics/Projects/UIProjectConversion/")),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/BlueprintMultiplayer/"},"https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/BlueprintMultiplayer/")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/86c50ec3.37681b55.js b/assets/js/86c50ec3.37681b55.js new file mode 100644 index 000000000000..d3bba5a3bb8d --- /dev/null +++ b/assets/js/86c50ec3.37681b55.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8625],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=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 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 l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=c(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,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(n),m=o,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(h,l(l({ref:t},u),{},{components:n})):r.createElement(h,l({ref:t},u))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,l=new Array(a);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,l[1]=i;for(var c=2;c<a;c++)l[c]=n[c];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},183:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={},l="Installing on Mac OS X",i={unversionedId:"host/installation/mac_os_x",id:"host/installation/mac_os_x",title:"Installing on Mac OS X",description:"1. Go to the root and run",source:"@site/docs/1_host/1_installation/2_mac_os_x.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/mac_os_x",permalink:"/etherealengine-docs/docs/host/installation/mac_os_x",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/2_mac_os_x.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Basic Setup",permalink:"/etherealengine-docs/docs/host/installation/basic_setup"},next:{title:"Installing on Windows 10+",permalink:"/etherealengine-docs/docs/host/installation/windows"}},s={},c=[{value:"Troubleshooting Mac",id:"troubleshooting-mac",level:2}],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"installing-on-mac-os-x"},"Installing on Mac OS X"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Go to the root and run")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm install\nnpm run dev-docker\nnpm run dev-reinit\n")),(0,o.kt)("p",null,"Or if you are on a M1 based Mac"),(0,o.kt)("p",null,"(Recommended)\n1) Duplicate the Terminal app, and configure it to run in Rosetta\n2) Run the above in Rosetta Terminal"),(0,o.kt)("p",null,"(Not recommended)"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"yarn install\n")),(0,o.kt)("p",null,"This is because on Apple chips the node-darwin sometimes doesn't get installed\nproperly and by using yarn it fixes the issue."),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"Have docker started in the background and then in the terminal type")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm run dev\n")),(0,o.kt)("p",null,"This will open the mariaDB and SQL scripts on the docker and will start the servers"),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"To make sure your environment is set and running properly just go to\nhttps://localhost:3000/location/default and you should be able to walk around an empty 3D scene")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Note : Make sure you are on Node >= 16 and have docker running. \n")),(0,o.kt)("h2",{id:"troubleshooting-mac"},"Troubleshooting Mac"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"If you find issues on your terminal that says that access-denied for user\n",(0,o.kt)("inlineCode",{parentName:"li"},"server@localhost")," then you can use this command")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"brew services stop mysql\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"If you find issue on your terminal that says\n",(0,o.kt)("inlineCode",{parentName:"li"},'An unexpected error occurred: "expected workspace package'),"\nwhile using yarn then you can use this command in your terminal")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"yarn policies set-version 1.18.0\n")),(0,o.kt)("p",null,"As yarn > 1.18 sometimes doesn't work properly with lerna."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8894.2c471ab3.js b/assets/js/8894.2c471ab3.js new file mode 100644 index 000000000000..c5ca8fc43b4d --- /dev/null +++ b/assets/js/8894.2c471ab3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8894],{8894:(e,s,n)=>{n.r(s)}}]); \ No newline at end of file diff --git a/assets/js/8df89772.0da26743.js b/assets/js/8df89772.0da26743.js new file mode 100644 index 000000000000..3270d88783d1 --- /dev/null +++ b/assets/js/8df89772.0da26743.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8620],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var n=r(7294);function o(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 l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function a(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=a(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return r?n.createElement(f,l(l({ref:t},c),{},{components:r})):n.createElement(f,l({ref:t},c))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,l=new Array(i);l[0]=m;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a[u]="string"==typeof e?e:o,l[1]=a;for(var p=2;p<i;p++)l[p]=r[p];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},4085:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>a,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const i={},l="Asset Import Pipeline",a={unversionedId:"creator/importing_assets/readme",id:"creator/importing_assets/readme",title:"Asset Import Pipeline",description:"WARNING: This page is out of date",source:"@site/docs/2_creator/3_importing_assets/readme.md",sourceDirName:"2_creator/3_importing_assets",slug:"/creator/importing_assets/",permalink:"/etherealengine-docs/docs/creator/importing_assets/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/3_importing_assets/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Studio Overview",permalink:"/etherealengine-docs/docs/creator/studio/"},next:{title:"Development",permalink:"/etherealengine-docs/docs/creator/development/"}},s={},p=[{value:"WARNING: This page is out of date",id:"warning-this-page-is-out-of-date",level:2},{value:"Collider Metadata",id:"collider-metadata",level:2}],c={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"asset-import-pipeline"},"Asset Import Pipeline"),(0,o.kt)("h1",{id:"omniverse"},"Omniverse"),(0,o.kt)("h1",{id:"unity"},"Unity"),(0,o.kt)("h1",{id:"unreal"},"Unreal"),(0,o.kt)("h1",{id:"blender"},"Blender"),(0,o.kt)("h2",{id:"warning-this-page-is-out-of-date"},"WARNING: This page is out of date"),(0,o.kt)("p",null,"The simplest pipeline uses Blender & the Studio's inbuilt transformation tool. "),(0,o.kt)("p",null,"Scenes that contain colliders should have these colliders exported separately.\nVisible meshes should not have collider metadata, instead a copy should be created."),(0,o.kt)("p",null,"The process of moving from Blender to Ethereal Engine looks like the following:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Blend file is the source of truth"),(0,o.kt)("li",{parentName:"ol"},"Export visible meshes from from blend file"),(0,o.kt)("li",{parentName:"ol"},"Export collider meshes from blend file with Custom Properties"),(0,o.kt)("li",{parentName:"ol"},"Import to editor"),(0,o.kt)("li",{parentName:"ol"},"Optimize visible glb with transformation tool"),(0,o.kt)("li",{parentName:"ol"},"Use final transformed visible glb & collider glb for live scene")),(0,o.kt)("h2",{id:"collider-metadata"},"Collider Metadata"),(0,o.kt)("p",null,"All fixed colliders should be a child of a separate root hierarchy."),(0,o.kt)("p",null,"The root object of the collider hiearchy must have ",(0,o.kt)("inlineCode",{parentName:"p"},"xrengine.collider.bodyType: Fixed"),"\nEach collider must be a child of the root object with ",(0,o.kt)("inlineCode",{parentName:"p"},"shapeType: <shape>")),(0,o.kt)("p",null,"The currently supported shapes are as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Cuboid"),(0,o.kt)("li",{parentName:"ul"},"Ball"),(0,o.kt)("li",{parentName:"ul"},"Capsule"),(0,o.kt)("li",{parentName:"ul"},"Cylinder"),(0,o.kt)("li",{parentName:"ul"},"ConvexPolyhedron"),(0,o.kt)("li",{parentName:"ul"},"TriMesh")),(0,o.kt)("p",null,"Other supported metadata for each collider is:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"friction: number"),(0,o.kt)("li",{parentName:"ul"},"restitution number"),(0,o.kt)("li",{parentName:"ul"},"collisionLayer: number"),(0,o.kt)("li",{parentName:"ul"},"collisionMask: number"),(0,o.kt)("li",{parentName:"ul"},"isTrigger: number")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/917fb754.1cd49318.js b/assets/js/917fb754.1cd49318.js new file mode 100644 index 000000000000..3c3650769fb0 --- /dev/null +++ b/assets/js/917fb754.1cd49318.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7053],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={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,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),f=o,m=p["".concat(l,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},2018:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={},i="Tutorials",c={unversionedId:"creator/tutorials/readme",id:"creator/tutorials/readme",title:"Tutorials",description:"In this section you will various tutorials for Ethereal Engine and its ecosystem.",source:"@site/docs/2_creator/5_tutorials/readme.md",sourceDirName:"2_creator/5_tutorials",slug:"/creator/tutorials/",permalink:"/etherealengine-docs/docs/creator/tutorials/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Introduction",permalink:"/etherealengine-docs/docs/creator/development/behave_graph"},next:{title:"Ethereal Engine",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/"}},l={},s=[],u={toc:s},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"tutorials"},"Tutorials"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine and its ecosystem."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.f14aaa66.js b/assets/js/935f2afb.f14aaa66.js new file mode 100644 index 000000000000..9c29b142ea16 --- /dev/null +++ b/assets/js/935f2afb.f14aaa66.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).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":"Overview","href":"/etherealengine-docs/docs/","docId":"overview"},{"type":"category","label":"Ethereal for Hosts","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Installation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Basic Setup","href":"/etherealengine-docs/docs/host/installation/basic_setup","docId":"host/installation/basic_setup"},{"type":"link","label":"Installing on Mac OS X","href":"/etherealengine-docs/docs/host/installation/mac_os_x","docId":"host/installation/mac_os_x"},{"type":"link","label":"Installing on Windows 10+","href":"/etherealengine-docs/docs/host/installation/windows","docId":"host/installation/windows"},{"type":"link","label":"Installing on Windows with WSL2","href":"/etherealengine-docs/docs/host/installation/windows_wsl","docId":"host/installation/windows_wsl"},{"type":"link","label":"Advanced Setup","href":"/etherealengine-docs/docs/host/installation/advanced_setup","docId":"host/installation/advanced_setup"},{"type":"link","label":"Running on Static IP under WSL2","href":"/etherealengine-docs/docs/host/installation/running_on_static_IP","docId":"host/installation/running_on_static_IP"},{"type":"link","label":"Troubleshooting","href":"/etherealengine-docs/docs/host/installation/install_troubleshooting","docId":"host/installation/install_troubleshooting"},{"type":"link","label":"Old Docker Instructions","href":"/etherealengine-docs/docs/host/installation/docker","docId":"host/installation/docker"},{"type":"link","label":"Logging with Opensearch on Docker","href":"/etherealengine-docs/docs/host/installation/opensearch","docId":"host/installation/opensearch"}],"href":"/etherealengine-docs/docs/host/installation/"},{"type":"category","label":"Deployment","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Ethereal Engine on MicroK8s (Linux)","href":"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux","docId":"host/devops_deployment/microk8s_linux"},{"type":"link","label":"Ethereal Engine on MicroK8s (Windows)","href":"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows","docId":"host/devops_deployment/microk8s_windows"},{"type":"link","label":"Ethereal Engine on Docker Desktop","href":"/etherealengine-docs/docs/host/devops_deployment/docker_desktop","docId":"host/devops_deployment/docker_desktop"},{"type":"link","label":"Ethereal Engine on Minikube","href":"/etherealengine-docs/docs/host/devops_deployment/minikube","docId":"host/devops_deployment/minikube"},{"type":"link","label":"Ethereal Engine on AWS","href":"/etherealengine-docs/docs/host/devops_deployment/AWS_setup","docId":"host/devops_deployment/AWS_setup"},{"type":"link","label":"Installing Projects","href":"/etherealengine-docs/docs/host/devops_deployment/installing_projects","docId":"host/devops_deployment/installing_projects"},{"type":"link","label":"Database Migrations","href":"/etherealengine-docs/docs/host/devops_deployment/database_migrations","docId":"host/devops_deployment/database_migrations"},{"type":"link","label":"How to set up GitHub to install external projects","href":"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects","docId":"host/devops_deployment/setup_github_oauth_for_projects"},{"type":"link","label":"Cluster Management","href":"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes","docId":"host/devops_deployment/managing_remote_kubernetes"},{"type":"link","label":"Release Helm Chart","href":"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart","docId":"host/devops_deployment/release_helm_chart"},{"type":"link","label":"Upgrading Helm Release","href":"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment","docId":"host/devops_deployment/upgrade_helm_deployment"},{"type":"category","label":"Tutorials","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Control Center App","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started","docId":"host/devops_deployment/tutorials/ethereal_control_center/getting_started"}],"href":"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/"}],"href":"/etherealengine-docs/docs/host/devops_deployment/tutorials/"}],"href":"/etherealengine-docs/docs/host/devops_deployment/"},{"type":"link","label":"Ethereal Engine Admin Panel Guide","href":"/etherealengine-docs/docs/host/Admin_Dashboard/","docId":"host/Admin_Dashboard/readme"}],"href":"/etherealengine-docs/docs/host/"},{"type":"category","label":"Ethereal for Creators","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Concepts","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Studio & Locations","href":"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations","docId":"creator/concepts/editor_scenes_locations"}],"href":"/etherealengine-docs/docs/creator/concepts/"},{"type":"link","label":"Studio Overview","href":"/etherealengine-docs/docs/creator/studio/","docId":"creator/studio/readme"},{"type":"link","label":"Asset Import Pipeline","href":"/etherealengine-docs/docs/creator/importing_assets/","docId":"creator/importing_assets/readme"},{"type":"category","label":"Development","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Projects","href":"/etherealengine-docs/docs/creator/development/projects_overview","docId":"creator/development/projects_overview"},{"type":"link","label":"State Management","href":"/etherealengine-docs/docs/creator/development/state_management","docId":"creator/development/state_management"},{"type":"link","label":"Entities, Components and Systems","href":"/etherealengine-docs/docs/creator/development/ecs","docId":"creator/development/ecs"},{"type":"link","label":"Networking","href":"/etherealengine-docs/docs/creator/development/networking","docId":"creator/development/networking"},{"type":"link","label":"Event Sourcing","href":"/etherealengine-docs/docs/creator/development/actions_event_sourcing","docId":"creator/development/actions_event_sourcing"},{"type":"link","label":"Introduction","href":"/etherealengine-docs/docs/creator/development/behave_graph","docId":"creator/development/behave_graph"}],"href":"/etherealengine-docs/docs/creator/development/"},{"type":"category","label":"Tutorials","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Ethereal Engine","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Unity Bridge","href":"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge","docId":"creator/tutorials/ethereal_engine/unity_bridge"},{"type":"link","label":"Unreal Bridge","href":"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge","docId":"creator/tutorials/ethereal_engine/unreal_bridge"}],"href":"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/"}],"href":"/etherealengine-docs/docs/creator/tutorials/"},{"type":"category","label":"Testing","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Testing Basics","href":"/etherealengine-docs/docs/creator/testing/testing_intro","docId":"creator/testing/testing_intro"},{"type":"link","label":"Writing Reasonable & Testable Code","href":"/etherealengine-docs/docs/creator/testing/reasonable_code","docId":"creator/testing/reasonable_code"},{"type":"link","label":"Writing Good Tests","href":"/etherealengine-docs/docs/creator/testing/test_driven_development","docId":"creator/testing/test_driven_development"},{"type":"link","label":"Debugging","href":"/etherealengine-docs/docs/creator/testing/debugging","docId":"creator/testing/debugging"},{"type":"link","label":"Debugging Engine in WSL on Phone/Headset","href":"/etherealengine-docs/docs/creator/testing/debugging_device_wsl","docId":"creator/testing/debugging_device_wsl"},{"type":"link","label":"Debugging Deployed Instanceservers (and other Kubernetes pods)","href":"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers","docId":"creator/testing/debugging_deployed_instanceservers"}],"href":"/etherealengine-docs/docs/creator/testing/"},{"type":"link","label":"readme","href":"/etherealengine-docs/docs/creator/avatars/","docId":"creator/avatars/readme"}],"href":"/etherealengine-docs/docs/creator/"},{"type":"link","label":"Ethereal for Guests","href":"/etherealengine-docs/docs/guest/","docId":"guest/readme"}]},"docs":{"creator/avatars/readme":{"id":"creator/avatars/readme","title":"readme","description":"","sidebar":"tutorialSidebar"},"creator/concepts/editor_scenes_locations":{"id":"creator/concepts/editor_scenes_locations","title":"Studio & Locations","description":"Scene Studio","sidebar":"tutorialSidebar"},"creator/concepts/readme":{"id":"creator/concepts/readme","title":"Concepts","description":"","sidebar":"tutorialSidebar"},"creator/development/actions_event_sourcing":{"id":"creator/development/actions_event_sourcing","title":"Event Sourcing","description":"Actions","sidebar":"tutorialSidebar"},"creator/development/behave_graph":{"id":"creator/development/behave_graph","title":"Introduction","description":"* Overview","sidebar":"tutorialSidebar"},"creator/development/ecs":{"id":"creator/development/ecs","title":"Entities, Components and Systems","description":"What is an ECS?","sidebar":"tutorialSidebar"},"creator/development/networking":{"id":"creator/development/networking","title":"Networking","description":"Networks","sidebar":"tutorialSidebar"},"creator/development/projects_overview":{"id":"creator/development/projects_overview","title":"Projects","description":"Projects are folders that contain all your custom code, assets and scenes. They","sidebar":"tutorialSidebar"},"creator/development/readme":{"id":"creator/development/readme","title":"Development","description":"In this section you will find out how to create your own projects with Ethereal Engine.","sidebar":"tutorialSidebar"},"creator/development/state_management":{"id":"creator/development/state_management","title":"State Management","description":"All of Ethereal Engine\'s state management uses hookstate and react. Together, these tools give reactive, declarative, and controlled state management across any scope.","sidebar":"tutorialSidebar"},"creator/importing_assets/readme":{"id":"creator/importing_assets/readme","title":"Asset Import Pipeline","description":"WARNING: This page is out of date","sidebar":"tutorialSidebar"},"creator/readme":{"id":"creator/readme","title":"Ethereal for Creators","description":"Learn how to create, code and customize projects with Ethereal Engine","sidebar":"tutorialSidebar"},"creator/studio/readme":{"id":"creator/studio/readme","title":"Studio Overview","description":"Ethereal Engine Studio","sidebar":"tutorialSidebar"},"creator/testing/debugging":{"id":"creator/testing/debugging","title":"Debugging","description":"This section covers different techniques for debugging the source code.","sidebar":"tutorialSidebar"},"creator/testing/debugging_deployed_instanceservers":{"id":"creator/testing/debugging_deployed_instanceservers","title":"Debugging Deployed Instanceservers (and other Kubernetes pods)","description":"Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear","sidebar":"tutorialSidebar"},"creator/testing/debugging_device_wsl":{"id":"creator/testing/debugging_device_wsl","title":"Debugging Engine in WSL on Phone/Headset","description":"This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11.","sidebar":"tutorialSidebar"},"creator/testing/readme":{"id":"creator/testing/readme","title":"Testing","description":"Automated testing is a cornerstone to successful software development. Tests are","sidebar":"tutorialSidebar"},"creator/testing/reasonable_code":{"id":"creator/testing/reasonable_code","title":"Writing Reasonable & Testable Code","description":"Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application.","sidebar":"tutorialSidebar"},"creator/testing/test_driven_development":{"id":"creator/testing/test_driven_development","title":"Writing Good Tests","description":"Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:","sidebar":"tutorialSidebar"},"creator/testing/testing_intro":{"id":"creator/testing/testing_intro","title":"Testing Basics","description":"","sidebar":"tutorialSidebar"},"creator/tutorials/ethereal_engine/readme":{"id":"creator/tutorials/ethereal_engine/readme","title":"Ethereal Engine","description":"In this section you will various tutorials for Ethereal Engine.","sidebar":"tutorialSidebar"},"creator/tutorials/ethereal_engine/unity_bridge":{"id":"creator/tutorials/ethereal_engine/unity_bridge","title":"Unity Bridge","description":"","sidebar":"tutorialSidebar"},"creator/tutorials/ethereal_engine/unreal_bridge":{"id":"creator/tutorials/ethereal_engine/unreal_bridge","title":"Unreal Bridge","description":"https://github.com/etherealengine/XRE-Bridge-Unreal","sidebar":"tutorialSidebar"},"creator/tutorials/readme":{"id":"creator/tutorials/readme","title":"Tutorials","description":"In this section you will various tutorials for Ethereal Engine and its ecosystem.","sidebar":"tutorialSidebar"},"guest/readme":{"id":"guest/readme","title":"Ethereal for Guests","description":"Whether you\'re a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine.","sidebar":"tutorialSidebar"},"host/Admin_Dashboard/readme":{"id":"host/Admin_Dashboard/readme","title":"Ethereal Engine Admin Panel Guide","description":"Dashboard","sidebar":"tutorialSidebar"},"host/devops_deployment/AWS_setup":{"id":"host/devops_deployment/AWS_setup","title":"Ethereal Engine on AWS","description":"The value RELEASE_NAME referenced throughout this guide is the name of the deployment, e.g. dev or prod.","sidebar":"tutorialSidebar"},"host/devops_deployment/database_migrations":{"id":"host/devops_deployment/database_migrations","title":"Database Migrations","description":"Create Migration File","sidebar":"tutorialSidebar"},"host/devops_deployment/docker_desktop":{"id":"host/devops_deployment/docker_desktop","title":"Ethereal Engine on Docker Desktop","description":"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.","sidebar":"tutorialSidebar"},"host/devops_deployment/installing_projects":{"id":"host/devops_deployment/installing_projects","title":"Installing Projects","description":"Local Install Flow","sidebar":"tutorialSidebar"},"host/devops_deployment/managing_remote_kubernetes":{"id":"host/devops_deployment/managing_remote_kubernetes","title":"Cluster Management","description":"Kubernetes Web UI (Dashboard)","sidebar":"tutorialSidebar"},"host/devops_deployment/microk8s_linux":{"id":"host/devops_deployment/microk8s_linux","title":"Ethereal Engine on MicroK8s (Linux)","description":"This guide is intended for local environment and currently tested on Ubuntu.","sidebar":"tutorialSidebar"},"host/devops_deployment/microk8s_windows":{"id":"host/devops_deployment/microk8s_windows","title":"Ethereal Engine on MicroK8s (Windows)","description":"This guide is intended for local environment and currently tested on Windows 11.","sidebar":"tutorialSidebar"},"host/devops_deployment/minikube":{"id":"host/devops_deployment/minikube","title":"Ethereal Engine on Minikube","description":"Install kubectl, Helm, Docker, and VirtualBox","sidebar":"tutorialSidebar"},"host/devops_deployment/readme":{"id":"host/devops_deployment/readme","title":"Deployment","description":"In this section you will find out how to deploy Ethereal Engine.","sidebar":"tutorialSidebar"},"host/devops_deployment/release_helm_chart":{"id":"host/devops_deployment/release_helm_chart","title":"Release Helm Chart","description":"Following are the steps that needs to be taken in order to update etherealengine helm charts repo:","sidebar":"tutorialSidebar"},"host/devops_deployment/setup_github_oauth_for_projects":{"id":"host/devops_deployment/setup_github_oauth_for_projects","title":"How to set up GitHub to install external projects","description":"Ethereal Engine is extensible via Projects, which can contain","sidebar":"tutorialSidebar"},"host/devops_deployment/tutorials/ethereal_control_center/getting_started":{"id":"host/devops_deployment/tutorials/ethereal_control_center/getting_started","title":"Getting Started","description":"The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster.","sidebar":"tutorialSidebar"},"host/devops_deployment/tutorials/ethereal_control_center/readme":{"id":"host/devops_deployment/tutorials/ethereal_control_center/readme","title":"Control Center App","description":"In this section you will various tutorials for Ethereal Engine Control System app.","sidebar":"tutorialSidebar"},"host/devops_deployment/tutorials/readme":{"id":"host/devops_deployment/tutorials/readme","title":"Tutorials","description":"In this section you will various tutorials for Ethereal Engine and its hosting techniques.","sidebar":"tutorialSidebar"},"host/devops_deployment/upgrade_helm_deployment":{"id":"host/devops_deployment/upgrade_helm_deployment","title":"Upgrading Helm Release","description":"This guide will cover various sections regarding upgrading an existing helm deployment.","sidebar":"tutorialSidebar"},"host/installation/advanced_setup":{"id":"host/installation/advanced_setup","title":"Advanced Setup","description":"If you want to setup Ethereal Engine docker instances, client, server, and/or","sidebar":"tutorialSidebar"},"host/installation/basic_setup":{"id":"host/installation/basic_setup","title":"Basic Setup","description":"","sidebar":"tutorialSidebar"},"host/installation/docker":{"id":"host/installation/docker","title":"Old Docker Instructions","description":"You can quickstart locally using docker, if you don\'t have node installed or","sidebar":"tutorialSidebar"},"host/installation/install_troubleshooting":{"id":"host/installation/install_troubleshooting","title":"Troubleshooting","description":"Browser Debug","sidebar":"tutorialSidebar"},"host/installation/mac_os_x":{"id":"host/installation/mac_os_x","title":"Installing on Mac OS X","description":"1. Go to the root and run","sidebar":"tutorialSidebar"},"host/installation/opensearch":{"id":"host/installation/opensearch","title":"Logging with Opensearch on Docker","description":"If you want to quickstart with detailed logging using opensearch, Please follow this guide.","sidebar":"tutorialSidebar"},"host/installation/readme":{"id":"host/installation/readme","title":"Installation","description":"Getting up and running requires just a few steps, but this can be tricky,","sidebar":"tutorialSidebar"},"host/installation/running_on_static_IP":{"id":"host/installation/running_on_static_IP","title":"Running on Static IP under WSL2","description":"Follow these steps to run the engine on a static IP instead of localhost. In","sidebar":"tutorialSidebar"},"host/installation/windows":{"id":"host/installation/windows","title":"Installing on Windows 10+","description":"1. Install python 3 and add python installation directory path to \'PATH\' env variable.","sidebar":"tutorialSidebar"},"host/installation/windows_wsl":{"id":"host/installation/windows_wsl","title":"Installing on Windows with WSL2","description":"This guide is currently tested on Windows 10 (22H2) and Windows 11.","sidebar":"tutorialSidebar"},"host/readme":{"id":"host/readme","title":"Ethereal for Hosts","description":"Learn how to host your own Ethereal Engine deployment","sidebar":"tutorialSidebar"},"overview":{"id":"overview","title":"Overview","description":"Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/95bfc3a6.52bf81df.js b/assets/js/95bfc3a6.52bf81df.js new file mode 100644 index 000000000000..c02fc5f844ea --- /dev/null +++ b/assets/js/95bfc3a6.52bf81df.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5459],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(r),m=o,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:o,i[1]=l;for(var c=2;c<a;c++)i[c]=r[c];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},9702:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=r(7462),o=(r(7294),r(3905));const a={},i="Tutorials",l={unversionedId:"host/devops_deployment/tutorials/readme",id:"host/devops_deployment/tutorials/readme",title:"Tutorials",description:"In this section you will various tutorials for Ethereal Engine and its hosting techniques.",source:"@site/docs/1_host/2_devops_deployment/8_tutorials/readme.md",sourceDirName:"1_host/2_devops_deployment/8_tutorials",slug:"/host/devops_deployment/tutorials/",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/8_tutorials/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Upgrading Helm Release",permalink:"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment"},next:{title:"Control Center App",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/"}},s={},c=[],p={toc:c},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"tutorials"},"Tutorials"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine and its hosting techniques."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9a2a3fee.080e864f.js b/assets/js/9a2a3fee.080e864f.js new file mode 100644 index 000000000000..c16c6260ded2 --- /dev/null +++ b/assets/js/9a2a3fee.080e864f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5229],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var r=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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(n),u=o,g=d["".concat(s,".").concat(u)]||d[u]||m[u]||a;return n?r.createElement(g,i(i({ref:t},c),{},{components:n})):r.createElement(g,i({ref:t},c))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var p=2;p<a;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3901:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const a={},i="Database Migrations",l={unversionedId:"host/devops_deployment/database_migrations",id:"host/devops_deployment/database_migrations",title:"Database Migrations",description:"Create Migration File",source:"@site/docs/1_host/2_devops_deployment/3_database_migrations.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/database_migrations",permalink:"/etherealengine-docs/docs/host/devops_deployment/database_migrations",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/3_database_migrations.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing Projects",permalink:"/etherealengine-docs/docs/host/devops_deployment/installing_projects"},next:{title:"How to set up GitHub to install external projects",permalink:"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects"}},s={},p=[{value:"Create Migration File",id:"create-migration-file",level:2},{value:"OpenAPI",id:"openapi",level:2}],c={toc:p},d="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"database-migrations"},"Database Migrations"),(0,o.kt)("h2",{id:"create-migration-file"},"Create Migration File"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"In your ethereal engine repo run following command")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," cd packages/server-core\n")),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"Afterward run following command to generate migration file: ",(0,o.kt)("inlineCode",{parentName:"li"},"TIMESTAMP_NAME.ts")," i.e. ",(0,o.kt)("inlineCode",{parentName:"li"},"20230418102549_eks-column.ts")," in ",(0,o.kt)("inlineCode",{parentName:"li"},"server-core")," folder.")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," npm run migrate:make -- {NAME}\n")),(0,o.kt)("p",null,"i.e."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," npm run migrate:make -- eks-column\n")),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"Move the migration file to your service's ",(0,o.kt)("inlineCode",{parentName:"li"},"migrations")," folder. i.e. ",(0,o.kt)("inlineCode",{parentName:"li"},"packages/server-core/src/setting/aws-setting/migrations")),(0,o.kt)("li",{parentName:"ol"},"Update that file with code to match your needs.")),(0,o.kt)("h2",{id:"openapi"},"OpenAPI"),(0,o.kt)("p",null,"Our server is set up with Swagger documentation to automatically generate from most endpoints. A few custom routes are not documented at this time, but most of the basic stuff is."),(0,o.kt)("p",null,"You can see the docs for a running Ethereal Engine instance locally at:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"https://localhost:3030/openapi\n")),(0,o.kt)("p",null,"Or on our ",(0,o.kt)("a",{parentName:"p",href:"https://api-dev.etherealengine.com/openapi"},"dev cluster")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a1c60d7a.aa5dd692.js b/assets/js/a1c60d7a.aa5dd692.js new file mode 100644 index 000000000000..dde70a2eb2d5 --- /dev/null +++ b/assets/js/a1c60d7a.aa5dd692.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8949],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),h=o,d=p["".concat(c,".").concat(h)]||p[h]||f[h]||a;return r?n.createElement(d,i(i({ref:t},u),{},{components:r})):n.createElement(d,i({ref:t},u))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var l=2;l<a;l++)i[l]=r[l];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}h.displayName="MDXCreateElement"},1144:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={},i="Ethereal for Guests",s={unversionedId:"guest/readme",id:"guest/readme",title:"Ethereal for Guests",description:"Whether you're a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine.",source:"@site/docs/3_guest/readme.md",sourceDirName:"3_guest",slug:"/guest/",permalink:"/etherealengine-docs/docs/guest/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/3_guest/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"readme",permalink:"/etherealengine-docs/docs/creator/avatars/"}},c={},l=[],u={toc:l},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-for-guests"},"Ethereal for Guests"),(0,o.kt)("p",null,"Whether you're a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a47a1e93.04128bc8.js b/assets/js/a47a1e93.04128bc8.js new file mode 100644 index 000000000000..104413ad3d99 --- /dev/null +++ b/assets/js/a47a1e93.04128bc8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5992,2130],{3905:(t,e,n)=>{n.d(e,{Zo:()=>c,kt:()=>m});var r=n(7294);function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function s(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function i(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?s(Object(n),!0).forEach((function(e){a(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function o(t,e){if(null==t)return{};var n,r,a=function(t,e){if(null==t)return{};var n,r,a={},s=Object.keys(t);for(r=0;r<s.length;r++)n=s[r],e.indexOf(n)>=0||(a[n]=t[n]);return a}(t,e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);for(r=0;r<s.length;r++)n=s[r],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(a[n]=t[n])}return a}var l=r.createContext({}),d=function(t){var e=r.useContext(l),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},c=function(t){var e=d(t.components);return r.createElement(l.Provider,{value:e},t.children)},g="mdxType",p={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},u=r.forwardRef((function(t,e){var n=t.components,a=t.mdxType,s=t.originalType,l=t.parentName,c=o(t,["components","mdxType","originalType","parentName"]),g=d(n),u=a,m=g["".concat(l,".").concat(u)]||g[u]||p[u]||s;return n?r.createElement(m,i(i({ref:e},c),{},{components:n})):r.createElement(m,i({ref:e},c))}));function m(t,e){var n=arguments,a=e&&e.mdxType;if("string"==typeof t||a){var s=n.length,i=new Array(s);i[0]=u;var o={};for(var l in e)hasOwnProperty.call(e,l)&&(o[l]=e[l]);o.originalType=t,o[g]="string"==typeof t?t:a,i[1]=o;for(var d=2;d<s;d++)i[d]=n[d];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},7878:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>d,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905)),s=n(496);const i={},o="Testing Basics",l={unversionedId:"creator/testing/testing_intro",id:"creator/testing/testing_intro",title:"Testing Basics",description:"",source:"@site/docs/2_creator/6_testing/1_testing_intro.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/testing_intro",permalink:"/etherealengine-docs/docs/creator/testing/testing_intro",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/1_testing_intro.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Testing",permalink:"/etherealengine-docs/docs/creator/testing/"},next:{title:"Writing Reasonable & Testable Code",permalink:"/etherealengine-docs/docs/creator/testing/reasonable_code"}},d={},c=[],g={toc:c},p="wrapper";function u(t){let{components:e,...n}=t;return(0,a.kt)(p,(0,r.Z)({},g,n,{components:e,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"testing-basics"},"Testing Basics"),(0,a.kt)(s.default,{mdxType:"Readme"}))}u.isMDXComponent=!0},496:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>s,metadata:()=>o,toc:()=>d});var r=n(7462),a=(n(7294),n(3905));const s={},i="Testing",o={unversionedId:"creator/testing/readme",id:"creator/testing/readme",title:"Testing",description:"Automated testing is a cornerstone to successful software development. Tests are",source:"@site/docs/2_creator/6_testing/readme.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/",permalink:"/etherealengine-docs/docs/creator/testing/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Unreal Bridge",permalink:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge"},next:{title:"Testing Basics",permalink:"/etherealengine-docs/docs/creator/testing/testing_intro"}},l={},d=[{value:"SMTP Testing",id:"smtp-testing",level:2},{value:"Unit tests",id:"unit-tests",level:2},{value:"Integration tests",id:"integration-tests",level:2},{value:"Unit vs Integration Tests (source)",id:"unit-vs-integration-tests-source",level:2},{value:"System tests",id:"system-tests",level:2},{value:"End-to-end tests",id:"end-to-end-tests",level:2},{value:"System vs End-to-end Tests (source)",id:"system-vs-end-to-end-tests-source",level:2},{value:"White-box vs Black-box testing",id:"white-box-vs-black-box-testing",level:2},{value:"The Testing Pyramid",id:"the-testing-pyramid",level:2}],c={toc:d},g="wrapper";function p(t){let{components:e,...n}=t;return(0,a.kt)(g,(0,r.Z)({},c,n,{components:e,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"testing"},"Testing"),(0,a.kt)("p",null,"Automated testing is a cornerstone to successful software development. Tests are\nnot just to ensure that your application is working as intended, they are also\nto ensure that ",(0,a.kt)("strong",{parentName:"p"},"existing features aren't broken by any newly introduced features\nor code"),", aka ",(0,a.kt)("strong",{parentName:"p"},"regression bugs"),". The latter tends to hold more value, as it\nmakes the software sturdy and less prone to these types of bugs during active\ndevelopment of a project. Regression bugs will quickly stall the development of\na project at a certain level of complexity, effectively preventing progress."),(0,a.kt)("h2",{id:"smtp-testing"},"SMTP Testing"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://mailtrap.io/inboxes"},"https://mailtrap.io/inboxes")),(0,a.kt)("p",null,"Add credentials in ",(0,a.kt)("inlineCode",{parentName:"p"},".env.local")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-dotenv"},"SMTP_HOST=smtp.mailtrap.io\nSMTP_PORT=2525\nSMTP_USER=<mailtrap-user>\nSMTP_PASS=<mailtrap-password>\n")),(0,a.kt)("h2",{id:"unit-tests"},"Unit tests"),(0,a.kt)("p",null,"Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const add2 = x => x + 2\n\nit('should add 2 to a given number', () => {\n strictEqual(add2(1), 3)\n})\n")),(0,a.kt)("h2",{id:"integration-tests"},"Integration tests"),(0,a.kt)("p",null,"Integration tests focus on testing bundles of code units. A composition of functions, for example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const addTwo = x => x + 2\nconst multThree = x => x * 3\nconst halve = x => x / 2\n\nconst algorithm = x => {\n x = addTwo(x)\n x = multThree(x)\n x = halve(x)\n return x\n}\n\nit('should apply the entire algorithm correctly', () => {\n strictEqual(algorithm(4), 9)\n})\n")),(0,a.kt)("h2",{id:"unit-vs-integration-tests-source"},"Unit vs Integration Tests (",(0,a.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-unit-testing-and-integration-testing/"},"source"),")"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Unit Testing"),(0,a.kt)("th",{parentName:"tr",align:null},"Integration Testing"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"In unit testing each module of the software is tested separately."),(0,a.kt)("td",{parentName:"tr",align:null},"In integration testing all modules of the the software are tested combined.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"In unit testing the tester knows the internal design of the software."),(0,a.kt)("td",{parentName:"tr",align:null},"In integration testing the tester doesn't know the internal design of the software.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Unit testing is performed first of all testing processes."),(0,a.kt)("td",{parentName:"tr",align:null},"Integration testing is performed after unit testing, and before system/end-to-end tests.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Unit testing is a white box testing."),(0,a.kt)("td",{parentName:"tr",align:null},"Integration testing is a black box testing.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Unit testing is performed by the developer."),(0,a.kt)("td",{parentName:"tr",align:null},"Integration testing is performed by the tester.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Detection of defects in unit testing is easy."),(0,a.kt)("td",{parentName:"tr",align:null},"Detection of defects in integration testing is difficult.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"It tests parts of the project without waiting for others to be completed."),(0,a.kt)("td",{parentName:"tr",align:null},"It tests only after the completion of all parts.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Unit testing is less costly."),(0,a.kt)("td",{parentName:"tr",align:null},"Integration testing is more costly.")))),(0,a.kt)("h2",{id:"system-tests"},"System tests"),(0,a.kt)("p",null,"System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test)."),(0,a.kt)("h2",{id:"end-to-end-tests"},"End-to-end tests"),(0,a.kt)("p",null,"End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow)."),(0,a.kt)("h2",{id:"system-vs-end-to-end-tests-source"},"System vs End-to-end Tests (",(0,a.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-system-testing-and-end-to-end-testing/"},"source"),")"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"System Testing"),(0,a.kt)("th",{parentName:"tr",align:null},"End-to-end Testing"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"In system testing, whole software or application is tested at a time."),(0,a.kt)("td",{parentName:"tr",align:null},"In end-to-end testing, behavioral flow of the software is tested.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"System testing only tests the specific software system."),(0,a.kt)("td",{parentName:"tr",align:null},"It tests the software system and the connected systems both.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"The functionality of the software is tested."),(0,a.kt)("td",{parentName:"tr",align:null},"Flow from end-to-end is tested.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"It validates the software system as per standards and specifications."),(0,a.kt)("td",{parentName:"tr",align:null},"It validated all the interfaces of the software.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Knowledge of interconnected systems is not required."),(0,a.kt)("td",{parentName:"tr",align:null},"Knowledge about interconnected systems is required.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"It is carried out once integration testing is performed."),(0,a.kt)("td",{parentName:"tr",align:null},"It is performed after the system testing.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"It is performed both manually and automated."),(0,a.kt)("td",{parentName:"tr",align:null},"It is generally performed manually.")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"It is the super set of end-to-end testing."),(0,a.kt)("td",{parentName:"tr",align:null},"It is considered as subset of the system testing.")))),(0,a.kt)("h2",{id:"white-box-vs-black-box-testing"},"White-box vs Black-box testing"),(0,a.kt)("p",null,"Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing."),(0,a.kt)("p",null,"Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing."),(0,a.kt)("h2",{id:"the-testing-pyramid"},"The Testing Pyramid"),(0,a.kt)("p",null,"A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution."),(0,a.kt)("p",null,"70% Unit tests"),(0,a.kt)("p",null,"20% Integration tests"),(0,a.kt)("p",null,"10% End-to-end tests"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"}," /```\\\n / E2E \\\n /_______\\\n / \\\n /Integration\\\n /_____________\\\n / \\\n / Unit \\\n/___________________\\\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a91c512d.b90fd2d8.js b/assets/js/a91c512d.b90fd2d8.js new file mode 100644 index 000000000000..0be42d573b6b --- /dev/null +++ b/assets/js/a91c512d.b90fd2d8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4449],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var o=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 a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),p=function(e){var t=o.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 o.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),c=p(n),u=r,k=c["".concat(s,".").concat(u)]||c[u]||h[u]||a;return n?o.createElement(k,l(l({ref:t},d),{},{components:n})):o.createElement(k,l({ref:t},d))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,l=new Array(a);l[0]=u;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[c]="string"==typeof e?e:r,l[1]=i;for(var p=2;p<a;p++)l[p]=n[p];return o.createElement.apply(null,l)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},6793:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>d});var o=n(7462),r=(n(7294),n(3905)),a=n(4401);const l={},i="Ethereal Engine on Docker Desktop",s={unversionedId:"host/devops_deployment/docker_desktop",id:"host/devops_deployment/docker_desktop",title:"Ethereal Engine on Docker Desktop",description:"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.",source:"@site/docs/1_host/2_devops_deployment/1_docker_desktop.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/docker_desktop",permalink:"/etherealengine-docs/docs/host/devops_deployment/docker_desktop",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/1_docker_desktop.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on MicroK8s (Windows)",permalink:"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows"},next:{title:"Ethereal Engine on Minikube",permalink:"/etherealengine-docs/docs/host/devops_deployment/minikube"}},p={},d=[{value:"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.",id:"note-udp-networking-does-not-work-properly-on-docker-desktop-as-of-this-writing-as-docker-desktop-does-not-expose-the-ip-addressesports-of-the-node-publicly-so-mediasoup-cannot-connect-over-udp-if-you-want-to-test-audiovideo-calling-or-networked-movements-please-use-minikube",level:2},{value:"Install kubectl, Helm, and Docker Desktop",id:"install-kubectl-helm-and-docker-desktop",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Enable Kubernetes in Docker Desktop",id:"enable-kubernetes-in-docker-desktop",level:2},{value:"Edit system hostfile to point EtherealEngine addresses to 127.0.0.1",id:"edit-system-hostfile-to-point-etherealengine-addresses-to-127001",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"Run build_docker_desktop.sh",id:"run-build_docker_desktopsh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],c={toc:d},h="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(h,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"ethereal-engine-on-docker-desktop"},"Ethereal Engine on Docker Desktop"),(0,r.kt)("h2",{id:"note-udp-networking-does-not-work-properly-on-docker-desktop-as-of-this-writing-as-docker-desktop-does-not-expose-the-ip-addressesports-of-the-node-publicly-so-mediasoup-cannot-connect-over-udp-if-you-want-to-test-audiovideo-calling-or-networked-movements-please-use-minikube"},"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube."),(0,r.kt)("h2",{id:"install-kubectl-helm-and-docker-desktop"},"Install kubectl, Helm, and Docker Desktop"),(0,r.kt)("p",null,"If ",(0,r.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl"),", ",(0,r.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm"),",\nand/or ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/linux-install/"},"Docker Desktop"),"\naren't already installed on your machine, install them. Windows and Mac Docker Desktop installation instructions\ncan be found ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/windows-install/"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/mac-install/"},"here"),"."),(0,r.kt)("p",null,"You may also need to install ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"Docker Compose")),(0,r.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,r.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local\nservices, you'll need to get the Ethereal Engine repo on your machine. This is most easily\ndone by running ",(0,r.kt)("inlineCode",{parentName:"p"},"git clone https://github.com/etherealengine/etherealengine.git")),(0,r.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,r.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,r.kt)("p",null,"If you run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,r.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,r.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,r.kt)("inlineCode",{parentName:"p"},"./scripts/build_minikube.sh"),"."),(0,r.kt)("h2",{id:"enable-kubernetes-in-docker-desktop"},"Enable Kubernetes in Docker Desktop"),(0,r.kt)("p",null,"Inside Docker Desktop, go to Settings. There should be a section for Kubernetes (as of this writing, located\nbetween ",(0,r.kt)("inlineCode",{parentName:"p"},"Docker Engine")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Software updates")," settings). Click on that, then check the checkbox for Enable Kuberentes,\nand then click the button Apply and restart. When Docker Desktop restarts, it should now run a minikube-like Kubernetes\ncluster on startup. The Kubernetes context for this should be named ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-desktop"),"."),(0,r.kt)("h2",{id:"edit-system-hostfile-to-point-etherealengine-addresses-to-127001"},"Edit system hostfile to point EtherealEngine addresses to 127.0.0.1"),(0,r.kt)("p",null,"You'll need to edit your hostfile to point certain domains to 127.0.0.1, which is how Docker Desktop routes traffic\nto its Kubernetes cluster. On Linux, this is done by running ",(0,r.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/hosts"),"."),(0,r.kt)("p",null,"Add the following line:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"127.0.0.1 local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org\n")),(0,r.kt)("p",null,"You should also see a section that looks like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"# Added by Docker Desktop\n# To allow the same kube context to work on the host and the container:\n127.0.0.1 kubernetes.docker.internal\n# End of section\n")),(0,r.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the Kubernetes cluster,\nwhere the nginx ingress server will redirect the traffic to the appropriate pod.\nThe section it automatically added is used for giving Docker containers, including the Kubernetes cluster,\naccess to the host machine."),(0,r.kt)("p",null,"Make sure to save this file after you've edited it. On Linux, at least, you need root permissions\nto edit it."),(0,r.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,r.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,r.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,r.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,r.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,r.kt)("p",null,"Make sure that kubectl is pointed at docker-desktop by running ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),",\nwhich should say 'docker-desktop'. You can also run ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts\nthat kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,r.kt)("p",null,"Once kubectl is pointed to docker-desktop, from the top of the Ethereal Engine repo, run\n",(0,r.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones\nand ",(0,r.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,r.kt)("p",null,"You can run ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in docker-desktop. After a minute or so,\nall of these pods should be in the Running state."),(0,r.kt)("h2",{id:"run-build_docker_desktopsh"},"Run build_docker_desktop.sh"),(0,r.kt)("p",null,"When docker desktop's Kubernetes cluster is running, run the following command from the root of the Ethereal Engine repo:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/build_docker_desktop.sh\n")),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,r.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your terminal:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,r.kt)("p",null,"The script builds the full-repo Docker image using several build arguments. Vite, which builds\nthe client files, uses some information from the MariaDB database created for local K8s deployments\nto fill in some variables, and needs database credentials. The script will supply default values\nfor all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST,\nVITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your Docker Desktop K8s deployment\naccessible on ",(0,r.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different\ndomain, then you'll have to set those three environment variables to what you want them to be (and also\nchange the hostfile records you made pointing those subdomains to 127.0.0.1)"),(0,r.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for\ndifferent services, it will only run the parts needed for that service. This may take up to 15 minutes,\nthough later builds should take less time as things are cached."),(0,r.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,r.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.dockerdesktop.template.values.yaml"},"template")," for this file in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,r.kt)("p",null,"If you are using local file server as explained a couple of steps earlier then, update 'local.values.yaml' variable ",(0,r.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. It's mandatory to point to ",(0,r.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,r.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,r.kt)("p",null,"Run the following command: ",(0,r.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine"),"."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,r.kt)("p",null,"After a minute or so, running ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api\nservers, and one client server in the Running state. Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers\n(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run\n",(0,r.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),".\nThe API pods will restart and will now not attempt to reinit the database on boot."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,r.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,r.kt)(a.ZP,{mdxType:"AcceptCertificates"}))}u.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>i});var o=n(7462),r=(n(7294),n(3905));const a={toc:[]},l="wrapper";function i(e){let{components:t,...n}=e;return(0,r.kt)(l,(0,o.Z)({},a,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,r.kt)("p",null,"Go to ",(0,r.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,r.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,r.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,r.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,r.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}i.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b04e8f41.076998ce.js b/assets/js/b04e8f41.076998ce.js new file mode 100644 index 000000000000..f60cc8db8fcf --- /dev/null +++ b/assets/js/b04e8f41.076998ce.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2142],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,h=d["".concat(c,".").concat(m)]||d[m]||u[m]||r;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l<r;l++)i[l]=n[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},1173:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var o=n(7462),a=(n(7294),n(3905));const r={},i="Studio & Locations",s={unversionedId:"creator/concepts/editor_scenes_locations",id:"creator/concepts/editor_scenes_locations",title:"Studio & Locations",description:"Scene Studio",source:"@site/docs/2_creator/1_concepts/1_editor_scenes_locations.md",sourceDirName:"2_creator/1_concepts",slug:"/creator/concepts/editor_scenes_locations",permalink:"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/1_concepts/1_editor_scenes_locations.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Concepts",permalink:"/etherealengine-docs/docs/creator/concepts/"},next:{title:"Studio Overview",permalink:"/etherealengine-docs/docs/creator/studio/"}},c={},l=[{value:"Scene Studio",id:"scene-studio",level:2},{value:"Locations & Instances",id:"locations--instances",level:2}],p={toc:l},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"studio--locations"},"Studio & Locations"),(0,a.kt)("h2",{id:"scene-studio"},"Scene Studio"),(0,a.kt)("p",null,"Navigating to ",(0,a.kt)("inlineCode",{parentName:"p"},"/studio")," will show you the projects page, where you can open existing projects or create a new one."),(0,a.kt)("p",null,"Opening a project will route you to ",(0,a.kt)("inlineCode",{parentName:"p"},"/studio/<projectName>")," where the project studio will load. From here, you can open a scene, which will route you again to ",(0,a.kt)("inlineCode",{parentName:"p"},"/studio/<projectName>/<sceneName>")),(0,a.kt)("p",null,"The scene consists of a list of 'nodes' which act as templates / prefabs. These are what you would normally expect in a scene studio, such as models, colliders and audio, but we also support a wide range of integrations, such as shopify, wordpress and even portals to let you traverse between worlds."),(0,a.kt)("p",null,"To save a scene with Ctrl+S or in the top left Hamburger menu."),(0,a.kt)("h2",{id:"locations--instances"},"Locations & Instances"),(0,a.kt)("p",null,"Locations can be thought of as instantiations of scene. This is how you connect your scene to a shared session."),(0,a.kt)("p",null,"Locations can be loaded via the ",(0,a.kt)("inlineCode",{parentName:"p"},"/location/<locationName>")," route, where ",(0,a.kt)("inlineCode",{parentName:"p"},"locationName")," is the name of the location. By default, the locations ",(0,a.kt)("inlineCode",{parentName:"p"},"default"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"apartment")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"sky-station")," are added."),(0,a.kt)("p",null,"An ",(0,a.kt)("strong",{parentName:"p"},"instance")," is an individual session running at a location, in which users are connected together in real time. This allows the deployment to scale events and locations to potentially millions of concurrent users without having to support them all on a single instance. "),(0,a.kt)("p",null,"There are two types of instances: ",(0,a.kt)("strong",{parentName:"p"},"world")," instances and ",(0,a.kt)("strong",{parentName:"p"},"media")," instances. World instances handle the spatial objects in the scene, such as avatars, vehicles and grabbables. Media instances handle realtime audio, video and screenshare. "),(0,a.kt)("p",null,"Media instances can be tied to a location, or exist ephemerally as a group call, called parties."),(0,a.kt)("p",null,"Instances can also be customised with the 'matchmaker' functionality to create private rooms."),(0,a.kt)("p",null,"Adding a new location is done from ",(0,a.kt)("inlineCode",{parentName:"p"},"/admin/locations")," route, and live instances can be viewed from ",(0,a.kt)("inlineCode",{parentName:"p"},"/admin/instances"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b5eb9e9a.4e889fbb.js b/assets/js/b5eb9e9a.4e889fbb.js new file mode 100644 index 000000000000..0e5aed3db2d3 --- /dev/null +++ b/assets/js/b5eb9e9a.4e889fbb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6658],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=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 a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=r,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||a;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var c=2;c<a;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7157:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var o=n(7462),r=(n(7294),n(3905));const a={},i="Installing on Windows 10+",l={unversionedId:"host/installation/windows",id:"host/installation/windows",title:"Installing on Windows 10+",description:"1. Install python 3 and add python installation directory path to 'PATH' env variable.",source:"@site/docs/1_host/1_installation/3_windows.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/windows",permalink:"/etherealengine-docs/docs/host/installation/windows",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/3_windows.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing on Mac OS X",permalink:"/etherealengine-docs/docs/host/installation/mac_os_x"},next:{title:"Installing on Windows with WSL2",permalink:"/etherealengine-docs/docs/host/installation/windows_wsl"}},s={},c=[],p={toc:c},d="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"installing-on-windows-10"},"Installing on Windows 10+"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Install python 3 and add python installation directory path to 'PATH' env variable."),(0,r.kt)("li",{parentName:"ol"},"Install node js"),(0,r.kt)("li",{parentName:"ol"},"Install Visual studio community edition with build tools.",(0,r.kt)("blockquote",{parentName:"li"},(0,r.kt)("p",{parentName:"blockquote"},"Note: If mediasoup is not installed properly then modify Visual studio setup to add c++ and Node.js support."))),(0,r.kt)("li",{parentName:"ol"},"Add path of MSbuild.exe (which is present in visual studio folder) into 'path' env variable (for example:",(0,r.kt)("inlineCode",{parentName:"li"}," C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin"),")"),(0,r.kt)("li",{parentName:"ol"},"Make sure to install all windows prerequisites for mediasoup as mentioned on: ",(0,r.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/#windows"},"https://mediasoup.org/documentation/v3/mediasoup/installation/#windows")),(0,r.kt)("li",{parentName:"ol"},"Install all dependencies using ",(0,r.kt)("inlineCode",{parentName:"li"},"npm i"),"."),(0,r.kt)("li",{parentName:"ol"},"If error persists then check for typos in environment variables."),(0,r.kt)("li",{parentName:"ol"},"If you are on Windows, you can use docker-compose to start the ",(0,r.kt)("inlineCode",{parentName:"li"},"scripts/docker-compose.yml")," file, or install mariadb and copy credentials (database name, username, password) from docker-compose or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.local")," -- you will need to create an empty database with the matching name.")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"./start-db.sh")," only needs to be run once. If the docker image has stopped, start it again with:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"docker container start etherealengine_db\n")),(0,r.kt)("ol",{start:8},(0,r.kt)("li",{parentName:"ol"},"Check your WSL config for any incorrect networking settings.\n",(0,r.kt)("a",{parentName:"li",href:"https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network"},"https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b68e3f8b.506d688c.js b/assets/js/b68e3f8b.506d688c.js new file mode 100644 index 000000000000..d645e015f9af --- /dev/null +++ b/assets/js/b68e3f8b.506d688c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[543],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>y});var r=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 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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={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,o=e.mdxType,i=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=o,y=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return n?r.createElement(y,a(a({ref:t},s),{},{components:n})):r.createElement(y,a({ref:t},s))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:o,a[1]=l;for(var p=2;p<i;p++)a[p]=n[p];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},450:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const i={},a="Deployment",l={unversionedId:"host/devops_deployment/readme",id:"host/devops_deployment/readme",title:"Deployment",description:"In this section you will find out how to deploy Ethereal Engine.",source:"@site/docs/1_host/2_devops_deployment/readme.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/",permalink:"/etherealengine-docs/docs/host/devops_deployment/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Logging with Opensearch on Docker",permalink:"/etherealengine-docs/docs/host/installation/opensearch"},next:{title:"Ethereal Engine on MicroK8s (Linux)",permalink:"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux"}},c={},p=[],s={toc:p},d="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"deployment"},"Deployment"),(0,o.kt)("p",null,"In this section you will find out how to deploy Ethereal Engine."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bddbf10d.1a3063ba.js b/assets/js/bddbf10d.1a3063ba.js new file mode 100644 index 000000000000..8d2f101344cd --- /dev/null +++ b/assets/js/bddbf10d.1a3063ba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8823],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",f={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,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(l,".").concat(d)]||u[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},2401:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={},i="Ethereal for Hosts",c={unversionedId:"host/readme",id:"host/readme",title:"Ethereal for Hosts",description:"Learn how to host your own Ethereal Engine deployment",source:"@site/docs/1_host/readme.md",sourceDirName:"1_host",slug:"/host/",permalink:"/etherealengine-docs/docs/host/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/etherealengine-docs/docs/"},next:{title:"Installation",permalink:"/etherealengine-docs/docs/host/installation/"}},l={},s=[],p={toc:s},u="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-for-hosts"},"Ethereal for Hosts"),(0,o.kt)("p",null,"Learn how to host your own Ethereal Engine deployment"))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c538f40f.489bcf12.js b/assets/js/c538f40f.489bcf12.js new file mode 100644 index 000000000000..fdd12d5307b6 --- /dev/null +++ b/assets/js/c538f40f.489bcf12.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3850],{3905:(e,r,t)=>{t.d(r,{Zo:()=>p,kt:()=>m});var n=t(7294);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?a(Object(t),!0).forEach((function(r){o(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function i(e,r){if(null==e)return{};var t,n,o=function(e,r){if(null==e)return{};var t,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=n.createContext({}),s=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c(c({},r),e)),t},p=function(e){var r=s(e.components);return n.createElement(l.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(t),f=o,m=u["".concat(l,".").concat(f)]||u[f]||d[f]||a;return t?n.createElement(m,c(c({ref:r},p),{},{components:t})):n.createElement(m,c({ref:r},p))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=f;var i={};for(var l in r)hasOwnProperty.call(r,l)&&(i[l]=r[l]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var s=2;s<a;s++)c[s]=t[s];return n.createElement.apply(null,c)}return n.createElement.apply(null,t)}f.displayName="MDXCreateElement"},8580:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>s});var n=t(7462),o=(t(7294),t(3905));const a={},c="Ethereal for Creators",i={unversionedId:"creator/readme",id:"creator/readme",title:"Ethereal for Creators",description:"Learn how to create, code and customize projects with Ethereal Engine",source:"@site/docs/2_creator/readme.md",sourceDirName:"2_creator",slug:"/creator/",permalink:"/etherealengine-docs/docs/creator/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine Admin Panel Guide",permalink:"/etherealengine-docs/docs/host/Admin_Dashboard/"},next:{title:"Concepts",permalink:"/etherealengine-docs/docs/creator/concepts/"}},l={},s=[],p={toc:s},u="wrapper";function d(e){let{components:r,...t}=e;return(0,o.kt)(u,(0,n.Z)({},p,t,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-for-creators"},"Ethereal for Creators"),(0,o.kt)("p",null,"Learn how to create, code and customize projects with Ethereal Engine"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c7af7f81.8ce45faa.js b/assets/js/c7af7f81.8ce45faa.js new file mode 100644 index 000000000000..6e5e18395575 --- /dev/null +++ b/assets/js/c7af7f81.8ce45faa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4380],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,l=e.originalType,s=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),u=c(n),h=o,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||l;return n?a.createElement(m,i(i({ref:t},p),{},{components:n})):a.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=n.length,i=new Array(l);i[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[u]="string"==typeof e?e:o,i[1]=r;for(var c=2;c<l;c++)i[c]=n[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6030:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=n(7462),o=(n(7294),n(3905)),l=n(4401);const i={},r="Ethereal Engine on MicroK8s (Linux)",s={unversionedId:"host/devops_deployment/microk8s_linux",id:"host/devops_deployment/microk8s_linux",title:"Ethereal Engine on MicroK8s (Linux)",description:"This guide is intended for local environment and currently tested on Ubuntu.",source:"@site/docs/1_host/2_devops_deployment/0_microk8s_linux.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/microk8s_linux",permalink:"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/0_microk8s_linux.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Deployment",permalink:"/etherealengine-docs/docs/host/devops_deployment/"},next:{title:"Ethereal Engine on MicroK8s (Windows)",permalink:"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows"}},c={},p=[{value:"Install Python 3",id:"install-python-3",level:2},{value:"Install Make",id:"install-make",level:2},{value:"Install kubectl, Helm and Docker",id:"install-kubectl-helm-and-docker",level:2},{value:"Download and install MicroK8s",id:"download-and-install-microk8s",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Enabling MicroK8s Addons",id:"enabling-microk8s-addons",level:2},{value:"Add MicroK8s to Kubectl",id:"add-microk8s-to-kubectl",level:2},{value:"(Optional) Add MicroK8s to Lens",id:"optional-add-microk8s-to-lens",level:2},{value:"Enable MicroK8s access for local docker",id:"enable-microk8s-access-for-local-docker",level:2},{value:"Verify and troubleshoot MicroK8s",id:"verify-and-troubleshoot-microk8s",level:2},{value:"Update system hostfile to point to MicroK8s",id:"update-system-hostfile-to-point-to-microk8s",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"(Optional) Install Elastic Search and Kibana using Helm for Server Logs",id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Run build_microk8s.sh",id:"run-build_microk8ssh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],u={toc:p},d="wrapper";function h(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-engine-on-microk8s-linux"},"Ethereal Engine on MicroK8s (Linux)"),(0,o.kt)("p",null,"This guide is intended for local environment and currently tested on Ubuntu."),(0,o.kt)("h2",{id:"install-python-3"},"Install Python 3"),(0,o.kt)("p",null,"In your WSL Ubuntu terminal, if python 3 (",(0,o.kt)("inlineCode",{parentName:"p"},"pip3 --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y python3-pip\n")),(0,o.kt)("p",null,"You can verify pip3 by using ",(0,o.kt)("inlineCode",{parentName:"p"},"pip3 --version")," command."),(0,o.kt)("h2",{id:"install-make"},"Install Make"),(0,o.kt)("p",null,"In your WSL Ubuntu terminal, if make (",(0,o.kt)("inlineCode",{parentName:"p"},"make --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y build-essential\n")),(0,o.kt)("p",null,"You can verify make by using ",(0,o.kt)("inlineCode",{parentName:"p"},"make --version")," command."),(0,o.kt)("h2",{id:"install-kubectl-helm-and-docker"},"Install kubectl, Helm and Docker"),(0,o.kt)("p",null,"If ",(0,o.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl"),", ",(0,o.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm")," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/get-docker/"},"Docker")," aren't already installed on your machine, install them."),(0,o.kt)("p",null,"You may also need to install ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"Docker Compose")),(0,o.kt)("h2",{id:"download-and-install-microk8s"},"Download and install MicroK8s"),(0,o.kt)("p",null,"Instructions can be found ",(0,o.kt)("a",{parentName:"p",href:"https://ubuntu.com/tutorials/install-a-local-kubernetes-with-microk8s#1-overview"},"here")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo snap install microk8s --classic --channel=1.26/stable\n")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.")),(0,o.kt)("p",null,"While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it."),(0,o.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,o.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/etherealengine/etherealengine.git etherealengine\n")),(0,o.kt)("p",null,"If ",(0,o.kt)("inlineCode",{parentName:"p"},".env.local")," file does not exist in the root of your repo folder then create it by duplicating ",(0,o.kt)("inlineCode",{parentName:"p"},".env.local.default"),"."),(0,o.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,o.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,o.kt)("p",null,"If you run ",(0,o.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,o.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,o.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,o.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,o.kt)("inlineCode",{parentName:"p"},"./scripts/build_microk8s.sh"),"."),(0,o.kt)("h2",{id:"enabling-microk8s-addons"},"Enabling MicroK8s Addons"),(0,o.kt)("p",null,"Execute following command in your terminal to enable MicroK8s addons"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3")),(0,o.kt)("h2",{id:"add-microk8s-to-kubectl"},"Add MicroK8s to Kubectl"),(0,o.kt)("p",null,"First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command in terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config delete-context microk8s\nkubectl config delete-cluster microk8s-cluster\nkubectl config delete-user microk8s-admin\n")),(0,o.kt)("p",null,"Now, we will add microk8s configuration to kubectl config. We can do this by using following commands. ",(0,o.kt)("a",{parentName:"p",href:"https://discuss.kubernetes.io/t/use-kubectl-with-microk8s/5313/6"},"Reference")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt\nkubectl config set-credentials microk8s-admin --token=\"$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')\"\nkubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin\n")),(0,o.kt)("p",null,"Afterwards you can use this newly create context by executing ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config use-context microk8s")),(0,o.kt)("p",null,"Now if you run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command then microk8s should be current context."),(0,o.kt)("h2",{id:"optional-add-microk8s-to-lens"},"(Optional) Add MicroK8s to Lens"),(0,o.kt)("p",null," If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool ",(0,o.kt)("a",{parentName:"p",href:"https://k8slens.dev/"},"Lens"),". Else you can print the configuration using following command:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"microk8s config")),(0,o.kt)("p",null,"Option 1: If you have kubectl already installed, use ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo gedit ~/.kube/config")," as add the above output in it.",(0,o.kt)("br",{parentName:"p"}),"\n","Option 2: In Lens, goto ",(0,o.kt)("inlineCode",{parentName:"p"},"File")," > ",(0,o.kt)("inlineCode",{parentName:"p"},"Add Cluster")," and paste the output of above command to add cluster."),(0,o.kt)("h2",{id:"enable-microk8s-access-for-local-docker"},"Enable MicroK8s access for local docker"),(0,o.kt)("p",null,"For MicroK8s we will be using MicroK8s local ",(0,o.kt)("a",{parentName:"p",href:"https://microk8s.io/docs/registry-built-in"},"registry")),(0,o.kt)("p",null,"Add the following lines to ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/docker/daemon.json"),". On Linux, this is done by running ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/docker/daemon.json"),". "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{ \n "insecure-registries" : ["localhost:32000"] \n}\n')),(0,o.kt)("p",null,"Afterwards, restart docker with: ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo systemctl restart docker")),(0,o.kt)("h2",{id:"verify-and-troubleshoot-microk8s"},"Verify and troubleshoot MicroK8s"),(0,o.kt)("p",null,"Run ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo microk8s inspect")," and check if there is any warning. Its recommended to fixed the warning for MicroK8s to work properly. Following are some of the warnings and their possible fixes:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"WARNING: This machine's hostname contains capital letters and/or underscores. This is not a valid name for a Kubernetes node, causing node registration to fail. Please change the machine's hostname or refer to the documentation for more details."),(0,o.kt)("p",{parentName:"li"},"Possible Fix: ",(0,o.kt)("a",{parentName:"p",href:"https://askubuntu.com/a/87687/1558816"},"https://askubuntu.com/a/87687/1558816"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"WARNING: The memory cgroup is not enabled. The cluster may not be functioning properly. Please ensure cgroups are enabled "),(0,o.kt)("p",{parentName:"li"},"Possible Fix: ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/canonical/microk8s/issues/1691#issuecomment-1265788228"},"https://github.com/canonical/microk8s/issues/1691#issuecomment-1265788228"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"WARNING: IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo iptables -P FORWARD ACCEPT")),(0,o.kt)("p",{parentName:"li"},"The change can be made persistent with: ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo apt-get install iptables-persistent"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"MicroK8s is not running. Use microk8s inspect for a deeper inspection."),(0,o.kt)("p",{parentName:"li"},"Possible Fix: ",(0,o.kt)("a",{parentName:"p",href:"https://lightrun.com/answers/canonical-microk8s-microk8s-is-not-running-microk8sinspect-showing-no-error"},"https://lightrun.com/answers/canonical-microk8s-microk8s-is-not-running-microk8sinspect-showing-no-error")),(0,o.kt)("p",{parentName:"li"},"Here this error cloud be due to conflicting kubectl being installed. Use this command to remove kubectl ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo rm -rf /usr/local/bin/kubectl")))),(0,o.kt)("h2",{id:"update-system-hostfile-to-point-to-microk8s"},"Update system hostfile to point to MicroK8s"),(0,o.kt)("p",null,"You'll need to edit your hostfile to point certain domains to host machine IP address. On Linux, this is done by running ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/hosts"),"."),(0,o.kt)("p",null,"Add/Update the following lines:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"127.0.0.1 local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org")),(0,o.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod."),(0,o.kt)("p",null,"Make sure to save this file after you've edited it. On Linux, at least, you need root permissions to edit it."),(0,o.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,o.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,o.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,o.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,o.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,o.kt)("p",null,"Make sure that kubectl is pointed at MicroK8s by running ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),", which should say 'microk8s'. You can also run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,o.kt)("p",null,"Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones and ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("p",null,"You can run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state."),(0,o.kt)("h2",{id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs"},"(Optional) Install Elastic Search and Kibana using Helm for Server Logs"),(0,o.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,o.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,o.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,o.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,o.kt)("p",null,"Now check if the cluster members are up: ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,o.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,o.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana")),(0,o.kt)("p",null,"Check if all the pods are ready: ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,o.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,o.kt)("inlineCode",{parentName:"p"},"http://localhost:5601")," in your browser"),(0,o.kt)("p",null,"In order to connect logger with elasticsearch, update ",(0,o.kt)("inlineCode",{parentName:"p"},"local.microk8s.template.values.yaml")," env ",(0,o.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"local.microk8s.template.values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("h2",{id:"run-build_microk8ssh"},"Run build_microk8s.sh"),(0,o.kt)("p",null,"When microk8s is running, run the following command from the root of the Ethereal Engine repo:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/build_microk8s.sh\n")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,o.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your terminal:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,o.kt)("p",null,"The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on ",(0,o.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)"),(0,o.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached."),(0,o.kt)("p",null,"Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting ",(0,o.kt)("a",{parentName:"p",href:"http://localhost:32000/v2/_catalog"},"http://localhost:32000/v2/_catalog"),"."),(0,o.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,o.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"template")," for this file in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,o.kt)("p",null,"If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable ",(0,o.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to ",(0,o.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,o.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,o.kt)("p",null,"Run the following command: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine"),"."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("p",null,"After a minute or so, running ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting ",(0,o.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),". The API pods will restart and will now not attempt to reinit the database on boot."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,o.kt)(l.ZP,{mdxType:"AcceptCertificates"}))}h.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>r});var a=n(7462),o=(n(7294),n(3905));const l={toc:[]},i="wrapper";function r(e){let{components:t,...n}=e;return(0,o.kt)(i,(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,o.kt)("p",null,"Go to ",(0,o.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,o.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,o.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,o.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,o.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}r.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cc938c89.e1255a30.js b/assets/js/cc938c89.e1255a30.js new file mode 100644 index 000000000000..c2788bd567e2 --- /dev/null +++ b/assets/js/cc938c89.e1255a30.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3709],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?s(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="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,a=e.mdxType,s=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||s;return n?r.createElement(h,i(i({ref:t},p),{},{components:n})):r.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=n.length,i=new Array(s);i[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var c=2;c<s;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},4458:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>s,metadata:()=>o,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const s={hide_table_of_contents:!0},i="Writing Good Tests",o={unversionedId:"creator/testing/test_driven_development",id:"creator/testing/test_driven_development",title:"Writing Good Tests",description:"Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:",source:"@site/docs/2_creator/6_testing/3_test_driven_development.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/test_driven_development",permalink:"/etherealengine-docs/docs/creator/testing/test_driven_development",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/3_test_driven_development.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Writing Reasonable & Testable Code",permalink:"/etherealengine-docs/docs/creator/testing/reasonable_code"},next:{title:"Debugging",permalink:"/etherealengine-docs/docs/creator/testing/debugging"}},l={},c=[{value:"Test-Driven Development (source)",id:"test-driven-development-source",level:2},{value:"Antipatterns",id:"antipatterns",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"writing-good-tests"},"Writing Good Tests"),(0,a.kt)("p",null,"Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Mock"),(0,a.kt)("li",{parentName:"ol"},"Run"),(0,a.kt)("li",{parentName:"ol"},"Assert")),(0,a.kt)("p",null,"First, mock up data for the input parameters."),(0,a.kt)("p",null,"Then, run the function with the input data to produce an output."),(0,a.kt)("p",null,"Finally, assert that the output is correct."),(0,a.kt)("h2",{id:"test-driven-development-source"},"Test-Driven Development (",(0,a.kt)("a",{parentName:"h2",href:"https://en.wikipedia.org/wiki/Test-driven_development"},"source"),")"),(0,a.kt)("p",null,"Test-driven development (TDD) is a software development process relying on software requirements being converted to test cases before software is fully developed, and tracking all software development by repeatedly testing the software against all test cases. This is as opposed to software being developed first and test cases created later. "),(0,a.kt)("p",null,"This methodology is extremely useful and productive, because it means that your code will ",(0,a.kt)("em",{parentName:"p"},"always")," have test coverage. Not only that, but you can save time by ensuring that the feature is working simply by virtue of the tests passing, instead of having to run the entire software to see whether or not the feature or module in question is functioning correctly."),(0,a.kt)("p",null,"The following sequence is based on the book Test-Driven Development by Example:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Add a test"),(0,a.kt)("p",{parentName:"li"},"The adding of a new feature begins by writing a test that passes if and ",(0,a.kt)("em",{parentName:"p"},"only")," if the feature's specifications are met. The developer can discover these specifications by asking about use cases and user stories. A key benefit of test-driven development is that it makes the developer focus on requirements before writing code. This is in contrast with the usual practice, where unit tests are only written after code.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Run all tests. The new test should fail for expected reasons"),(0,a.kt)("p",{parentName:"li"},"This shows that new code is actually needed for the desired feature. It validates that the test harness is working correctly. It rules out the possibility that the new test is flawed and will always pass.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Write the simplest code that passes the new test"),(0,a.kt)("p",{parentName:"li"},"Inelegant or hard code is acceptable, as long as it passes the test. The code will be honed anyway in Step 5. No code should be added beyond the tested functionality.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"All tests should now pass"),(0,a.kt)("p",{parentName:"li"},"If any fail, the new code must be revised until they pass. This ensures the new code meets the test requirements and does not break existing features.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Refactor as needed, using tests after each refactor to ensure that functionality is preserved"),(0,a.kt)("p",{parentName:"li"},"Code is refactored for readability and maintainability. In particular, hard-coded test data should be removed. Running the test suite after each refactor helps ensure that no existing functionality is broken."),(0,a.kt)("p",{parentName:"li"},"Examples of refactoring:"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"moving code to where it most logically belongs"),(0,a.kt)("li",{parentName:"ul"},"removing duplicate code"),(0,a.kt)("li",{parentName:"ul"},"making names self-documenting"),(0,a.kt)("li",{parentName:"ul"},"splitting methods into smaller pieces"),(0,a.kt)("li",{parentName:"ul"},"re-arranging inheritance hierarchies")))),(0,a.kt)("p",null,"The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply undo or revert rather than debug excessively. When using external libraries, it is important not to write tests that are so small as to effectively test merely the library itself, unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development."),(0,a.kt)("h3",{id:"antipatterns"},"Antipatterns"),(0,a.kt)("p",null,'Practices to avoid, or "anti-patterns"'),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Having test cases depend on system state manipulated from previously executed test cases (i.e., you should always start a unit test from a known and pre-configured state)."),(0,a.kt)("li",{parentName:"ul"},"Dependencies between test cases. A test suite where test cases are dependent upon each other is brittle and complex. Execution order should not be presumed. Basic refactoring of the initial test cases or structure of the UUT causes a spiral of increasingly pervasive impacts in associated tests."),(0,a.kt)("li",{parentName:"ul"},"Interdependent tests. Interdependent tests can cause cascading false negatives. A failure in an early test case breaks a later test case even if no actual fault exists in the UUT, increasing defect analysis and debug efforts."),(0,a.kt)("li",{parentName:"ul"},"Testing precise execution behavior timing or performance."),(0,a.kt)("li",{parentName:"ul"},'Building "all-knowing oracles". An oracle that inspects more than necessary is more expensive and brittle over time. This very common error is dangerous because it causes a subtle but pervasive time sink across the complex project.'),(0,a.kt)("li",{parentName:"ul"},"Testing implementation details."),(0,a.kt)("li",{parentName:"ul"},"Slow running tests.")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cf339e2e.43e40fa8.js b/assets/js/cf339e2e.43e40fa8.js new file mode 100644 index 000000000000..d20147f4c4c0 --- /dev/null +++ b/assets/js/cf339e2e.43e40fa8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4438],{5745:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-pages","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/d05402c5.9693efa0.js b/assets/js/d05402c5.9693efa0.js new file mode 100644 index 000000000000..af0ff6c83b14 --- /dev/null +++ b/assets/js/d05402c5.9693efa0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6970],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=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 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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}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},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(n),h=o,f=u["".concat(s,".").concat(h)]||u[h]||d[h]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:o,a[1]=c;for(var l=2;l<i;l++)a[l]=n[l];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6064:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={},a="Event Sourcing",c={unversionedId:"creator/development/actions_event_sourcing",id:"creator/development/actions_event_sourcing",title:"Event Sourcing",description:"Actions",source:"@site/docs/2_creator/4_development/4_actions_event_sourcing.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/actions_event_sourcing",permalink:"/etherealengine-docs/docs/creator/development/actions_event_sourcing",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/4_actions_event_sourcing.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Networking",permalink:"/etherealengine-docs/docs/creator/development/networking"},next:{title:"Introduction",permalink:"/etherealengine-docs/docs/creator/development/behave_graph"}},s={},l=[{value:"Actions",id:"actions",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...i}=e;return(0,o.kt)(u,(0,r.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"event-sourcing"},"Event Sourcing"),(0,o.kt)("h2",{id:"actions"},"Actions"),(0,o.kt)("p",null,"Actions are a way to control state changes in your application. Once defined, they can be dispatched, which will then populate the outgoing queue to be processed on the next frame."),(0,o.kt)("p",null,"All actions are dispatched to a topic, by default this is the ",(0,o.kt)("strong",{parentName:"p"},"default")," topic. Topics are used to specify that actions are to be routed to specific networks."),(0,o.kt)("p",null,"When an action is dispatched, it is added to the incoming action queue. If it's topic is networked, it is also added to the outgoing queue for it's topic."),(0,o.kt)("p",null,"At the end of the animation frame, any actions in a network topic's outgoing queue are sent to that topic's network."),(0,o.kt)("p",null,"If the peer is the host of a networked action's topic, the action is sent to all other peers, otherwise it is just sent to the host. This can be opted out of by specifying the $to property on an action, which informs the host to forward the action only to that user's."),(0,o.kt)("p",null,"At the start of the next animation frame, action queues are populated with incoming actions. These actions are then processed in the order they were received, by systems in the order the systems are registered."),(0,o.kt)("p",null,(0,o.kt)("img",{src:n(8608).Z,width:"1229",height:"389"})))}d.isMDXComponent=!0},8608:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png"}}]); \ No newline at end of file diff --git a/assets/js/d43455fa.4acf96f4.js b/assets/js/d43455fa.4acf96f4.js new file mode 100644 index 000000000000..877195f35535 --- /dev/null +++ b/assets/js/d43455fa.4acf96f4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1205],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=o.createContext({}),l=function(e){var t=o.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return o.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=l(n),u=a,h=m["".concat(p,".").concat(u)]||m[u]||d[u]||r;return n?o.createElement(h,i(i({ref:t},c),{},{components:n})):o.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=u;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var l=2;l<r;l++)i[l]=n[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},9347:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var o=n(7462),a=(n(7294),n(3905));const r={},i="Entities, Components and Systems",s={unversionedId:"creator/development/ecs",id:"creator/development/ecs",title:"Entities, Components and Systems",description:"What is an ECS?",source:"@site/docs/2_creator/4_development/2_ecs.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/ecs",permalink:"/etherealengine-docs/docs/creator/development/ecs",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/2_ecs.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"State Management",permalink:"/etherealengine-docs/docs/creator/development/state_management"},next:{title:"Networking",permalink:"/etherealengine-docs/docs/creator/development/networking"}},p={},l=[{value:"What is an ECS?",id:"what-is-an-ecs",level:2},{value:"Component Definitions",id:"component-definitions",level:2},{value:"Structure of Arrays Component Data",id:"structure-of-arrays-component-data",level:3},{value:"Reactive Component Data",id:"reactive-component-data",level:3},{value:"onInit",id:"oninit",level:3},{value:"onSet",id:"onset",level:3},{value:"onRemove",id:"onremove",level:3},{value:"toJSON",id:"tojson",level:3},{value:"jsonID",id:"jsonid",level:2},{value:"reactor",id:"reactor",level:3},{value:"Update Loop",id:"update-loop",level:2},{value:"Queries",id:"queries",level:2},{value:"Examples",id:"examples",level:2},{value:"Timer",id:"timer",level:3},{value:"References",id:"references",level:2}],c={toc:l},m="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"entities-components-and-systems"},"Entities, Components and Systems"),(0,a.kt)("h2",{id:"what-is-an-ecs"},"What is an ECS?"),(0,a.kt)("p",null,'ECS refers to the "Entity Component System" architecture paradigm. In this pattern, data is organised into abstract objects called ',(0,a.kt)("strong",{parentName:"p"},"components")," that allows for composition instead of inheritance. An ",(0,a.kt)("strong",{parentName:"p"},"entity")," is simply collection of components identified by a number. ",(0,a.kt)("strong",{parentName:"p"},"Systems")," are functions that operate on these entities and components."),(0,a.kt)("h2",{id:"component-definitions"},"Component Definitions"),(0,a.kt)("p",null,"Components support two types of data: Structure of Arrays and Array of Structures."),(0,a.kt)("h3",{id:"structure-of-arrays-component-data"},"Structure of Arrays Component Data"),(0,a.kt)("p",null,"Structure of Arrays is a data layout that stores data in a way that is more cache friendly. It is a good choice for data that is accessed often and in a predictable way, such as transform data."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const TransformComponent = defineComponent({\n name: 'TransformComponent',\n schema: {\n position: Types.f64,\n rotation: Types.f64,\n scale: Types.f64\n }\n})\n")),(0,a.kt)("h3",{id:"reactive-component-data"},"Reactive Component Data"),(0,a.kt)("p",null,"Array of Structures is an implementation unique to Ethereal Engine, using React and Hookstate under the hood, it allows for reactive data binding. This means that when a property is changed, all effects depending on it will be triggered. It is a good choice for data that is accessed infrequently and in an unpredictable way, especially when react style logic is associated with it."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const DebugArrowComponent = defineComponent({\n name: 'DebugArrowComponent',\n\n onInit: (entity) => {\n return {\n color: 0xffffff,\n direction: new Vector3(),\n position: new Vector3()\n }\n },\n\n onSet: (entity, component, json) => {\n if (!json) return\n\n if (json.color) component.color.set(json.color)\n if (json.direction) component.direction.set(json.direction)\n if (json.position) component.position.set(json.position)\n }\n})\n")),(0,a.kt)("h3",{id:"oninit"},"onInit"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"(entity: Entity) => ComponentType<C>")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"onInit")," is a function that is called when ",(0,a.kt)("strong",{parentName:"p"},"setComponent")," is called on an entity that does not have the component in question. It is passed the entity number and should return an object with the initial values for the component."),(0,a.kt)("h3",{id:"onset"},"onSet"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"entity: Entity, component: ComponentType<C>, json: SerializedComponentType<C>) => void")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"onSet")," is a function that is called each time ",(0,a.kt)("strong",{parentName:"p"},"setComponent")," is called. It is passed the entity number, the component object and json object. This is how reactive data can be updated in batch, allowing for tighter data flow, such as deserializing scene data."),(0,a.kt)("h3",{id:"onremove"},"onRemove"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"(entity: Entity, component: ComponentType<C>) => void")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"onRemove")," is a function that is called when ",(0,a.kt)("strong",{parentName:"p"},"removeComponent")," is called on an entity that has the component in question. It is passed the entity number and the component object. This is where you would clean up any resources associated with the component."),(0,a.kt)("h3",{id:"tojson"},"toJSON"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"(entity: Entity, component: ComponentType<C>) => SerializedComponentType<C>")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"toJSON")," is a function that is called when ",(0,a.kt)("strong",{parentName:"p"},"serializeComponent")," is called on an entity that has the component in question. It is passed the entity number and the component object. This is where serialized data can be generated, such as for saving a scene."),(0,a.kt)("h2",{id:"jsonid"},"jsonID"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"string")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"jsonID")," is a string that is used to identify the component in json. It is used when deserializing and serializing scenes."),(0,a.kt)("h3",{id:"reactor"},"reactor"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"function(props: { root: EntityRoot }) => void")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"reactor")," specifies a function that exists for the duration of this component instance. This is where you would add any effects that depend on the component."),(0,a.kt)("h2",{id:"update-loop"},"Update Loop"),(0,a.kt)("p",null,"The engine uses a very similar model to Unity's update loop (found here ",(0,a.kt)("a",{parentName:"p",href:"https://docs.unity3d.com/Manual/ExecutionOrder.html"},"https://docs.unity3d.com/Manual/ExecutionOrder.html"),"). It has a frame update, called once per frame, of which inside is a fixed update, which operates on an accumulator system. This system ensures a stable number of updates per second independent of the framerate. This means it may have 0 to many updates in a given frame. "),(0,a.kt)("p",null,"Ethereal Engine implements this with ",(0,a.kt)("strong",{parentName:"p"},"pipelines"),", which are collections of systems to execute in order."),(0,a.kt)("h2",{id:"queries"},"Queries"),(0,a.kt)("p",null,"Queries are used to select entities that have a set of components. They are used to define the entities that a system will operate on. Queries are defined using the ",(0,a.kt)("strong",{parentName:"p"},"defineQuery")," function."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const query = defineQuery([TransformComponent, GroupComponent])\n\nconst entities = query() // returns an array of entity numbers\n")),(0,a.kt)("p",null,"Queries also have enter and exit derivatives, which are used to define when a combination of components is added or removed from an entity. These are defined using the ",(0,a.kt)("strong",{parentName:"p"},"defineEnterQuery")," and ",(0,a.kt)("strong",{parentName:"p"},"defineExitQuery")," functions."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const query = defineQuery([TransformComponent, GroupComponent])\n\nconst allEntities = query()\nconst enterEntities = query.enter()\nconst exitEntities = query.exit()\n")),(0,a.kt)("h2",{id:"examples"},"Examples"),(0,a.kt)("h3",{id:"timer"},"Timer"),(0,a.kt)("p",null,"The follow code snippets, we define a component and a system. The component will hold a property to store the current elapsed time rounded down."),(0,a.kt)("p",null,"In the ",(0,a.kt)("strong",{parentName:"p"},"initializer")," of the system, it creates a new entity and adds the component to it. In the ",(0,a.kt)("strong",{parentName:"p"},"execute")," function of the system, we set the property ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," on the component of the entity."),(0,a.kt)("p",null,"This example uses 'Structure of Arrays' (SoA) data structures with bitECS syntax."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const TimerComponent = defineComponent({\n name: 'TimerComponent',\n schema: {\n time: Types.f32\n }\n})\n\nconst timerQuery = defineQuery([TimerComponent])\n\nconst execute = () => {\n const { deltaSeconds } = getState(EngineState)\n\n for (const entity of timerQuery()) {\n TimerComponent.time[entity] += delta\n }\n}\n\nexport const TimerSystem = defineSystem({\n uuid: 'TimerSystem',\n execute\n})\n\n")),(0,a.kt)("p",null,"This example uses 'Array of Structures' syntax, with reactive data binding."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const TimerComponent = defineComponent({\n name: 'TimerComponent',\n onInit: (entity) => {\n return {\n time: 0\n }\n },\n onSet: (entity, component, json) => {\n if (typeof json?.time === 'number') component.time.set(json.time)\n },\n toJSON: (entity, component) => {\n return {\n time: component.time.value\n }\n }\n})\n\nconst timerQuery = defineQuery([TimerComponent])\n\nconst execute = () => {\n const { elapsedSeconds } = getState(EngineState)\n\n for (const entity of timerQuery()) {\n const timerComponent = getMutableComponent(entity, TimerComponent)\n timerComponent.time.set(Math.floor(elapsedSeconds))\n }\n}\n\nexport const TimerSystem = defineSystem({\n uuid: 'TimerSystem',\n execute\n})\n\n")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=2rW7ALyHaas"},"Entity Component System Overview in 7 Minutes")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=qaY_CKvFLYM"},"Entity Component System in TypeScript with Phaser 3 and bitECS)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=W3aieHjyNvw"},"Overwatch GDC ECS & Netcode")," (note, ethereal engine does not use this style of networking)")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d50cf8bd.84d91e0f.js b/assets/js/d50cf8bd.84d91e0f.js new file mode 100644 index 000000000000..35a1ac92aabf --- /dev/null +++ b/assets/js/d50cf8bd.84d91e0f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1364],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var r=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 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 s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),p=c(n),g=o,h=p["".concat(l,".").concat(g)]||p[g]||u[g]||a;return n?r.createElement(h,s(s({ref:t},d),{},{components:n})):r.createElement(h,s({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=g;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:o,s[1]=i;for(var c=2;c<a;c++)s[c]=n[c];return r.createElement.apply(null,s)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},9466:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={},s="Debugging Deployed Instanceservers (and other Kubernetes pods)",i={unversionedId:"creator/testing/debugging_deployed_instanceservers",id:"creator/testing/debugging_deployed_instanceservers",title:"Debugging Deployed Instanceservers (and other Kubernetes pods)",description:"Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear",source:"@site/docs/2_creator/6_testing/6_debugging_deployed_instanceservers.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/debugging_deployed_instanceservers",permalink:"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/6_debugging_deployed_instanceservers.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Debugging Engine in WSL on Phone/Headset",permalink:"/etherealengine-docs/docs/creator/testing/debugging_device_wsl"},next:{title:"readme",permalink:"/etherealengine-docs/docs/creator/avatars/"}},l={},c=[],d={toc:c},p="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"debugging-deployed-instanceservers-and-other-kubernetes-pods"},"Debugging Deployed Instanceservers (and other Kubernetes pods)"),(0,o.kt)("p",null,"Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear\nbefore one has a chance to view them, as the pods that they were on are deleted, along with their logs."),(0,o.kt)("p",null,"One way to catch these errors is to tail the logs of existing pods from a local machine and then trigger the error.\nThe tail of the logs will persist in your terminal even after the pod has been deleted."),(0,o.kt)("p",null,"You should already have kubectl set up and pointing to your cluster, but if not, do so.\n(see ",(0,o.kt)("a",{parentName:"p",href:"../2_devops_deployment/5_managing_remote_kubernetes.md"},"here")," for links to do that)\nMake sure you don't have a browser tab with the offending location(s) open already, as you want to be tailing\nthe logs before the instance starts."),(0,o.kt)("p",null,"Next, run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get gs"),". If the cluster is fully installed, this will get all of the running instanceserver\npods (",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," will get all pods, if you need to find the names of API pods, etc.)\nSelect the Name of a pod and copy it (in Linux, highlight it and press CTRL+SHIFT+C), then run\n",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs <pod_name> -c <RELEASE_NAME>-instanceserver -f"),",\ne.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs prod-instanceserver-vhwh2-9vqrv -c prod-instanceserver -f"),". It should output something like this for\nand instanceserver pod:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'> @etherealengine/instanceserver@1.3.0 start\n> cross-env APP_ENV=production ts-node --swc src/index.ts\n\n\ud83d\udc7e bitECS - resizing all data stores from 100000 to 5000\n Powered by three.quarks. https://quarks.art/\n[hyperflux:Action] Added topic default\n[hyperflux:State] registerState SceneState\n[hyperflux:Action] Added Receptor EngineEventReceptor\n[hyperflux:State] registerState EngineState\n[hyperflux:State] registerState ServerState\nTue, 11 Jul 2023 00:38:50 GMT koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md at ../../node_modules/@feathersjs/koa/lib/index.js:52:27\n[00:38:50.631] INFO: Starting app.\n component: "server-core:sequelize"\n[hyperflux:State] registerState NetworkState\n[00:38:50.645] INFO: Starting app.\n component: "server-core:mysql"\n[00:38:50.900] INFO: registered kickCreatedListener\n component: "instanceserver:channels"\n[00:38:50.901] INFO: Starting instanceserver with NO HTTPS on 3031, if you meant to use HTTPS try \'sudo bash generate-certs\'\n component: "instanceserver"\n[00:38:51.036] INFO: Feathers-sync started.\n component: "server-core"\n[00:38:51.634] INFO: Server Ready\n component: "server-core:sequelize"\n\n')),(0,o.kt)("p",null,"Since the instanceserver pod that is picked to handle a given world or media instance is random, you'll want to\nopen a few more tabs in your terminal and repeat the above ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs")," command, substituting a different\ninstanceserver pod name in each tab, so that you're tailing all of the current pods. Then go to the location that is\ndisplaying problematic behavior, or otherwise trigger the action that is causing problems, and you should see the error\nin one of the terminals. If it's a fatal error, the logging will end with the pod, but the logs will stay in that terminal."),(0,o.kt)("p",null,"Note that if you want to log further errors, you may need to get the names of the new pods that are spun up to replace\nthe ones that crashed by running ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get gs")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," again, and then using the new pods' names in\n",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs")," commands."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d519f5a1.4eec9ca7.js b/assets/js/d519f5a1.4eec9ca7.js new file mode 100644 index 000000000000..4e8fa8bc4dcd --- /dev/null +++ b/assets/js/d519f5a1.4eec9ca7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5046],{3905:(e,t,n)=>{n.d(t,{Zo:()=>h,kt:()=>g});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 l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}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},h=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={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,o=e.mdxType,i=e.originalType,s=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),u=p(n),c=o,g=u["".concat(s,".").concat(c)]||u[c]||d[c]||i;return n?a.createElement(g,l(l({ref:t},h),{},{components:n})):a.createElement(g,l({ref:t},h))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=c;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[u]="string"==typeof e?e:o,l[1]=r;for(var p=2;p<i;p++)l[p]=n[p];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},806:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={},l="Introduction",r={unversionedId:"creator/development/behave_graph",id:"creator/development/behave_graph",title:"Introduction",description:"* Overview",source:"@site/docs/2_creator/4_development/5_behave_graph.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/behave_graph",permalink:"/etherealengine-docs/docs/creator/development/behave_graph",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/5_behave_graph.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Event Sourcing",permalink:"/etherealengine-docs/docs/creator/development/actions_event_sourcing"},next:{title:"Tutorials",permalink:"/etherealengine-docs/docs/creator/tutorials/"}},s={},p=[{value:"1. Introduction",id:"1-introduction",level:2},{value:"1.1 Overview",id:"11-overview",level:3},{value:"1.2 Audience",id:"12-audience",level:3},{value:"2. Getting Started",id:"2-getting-started",level:2},{value:"2.1 Installation - at the moment the behavior graph implementation is available on the behave-graph-integration branch in the Ethereal Engine Repository",id:"21-installation---at-the-moment-the-behavior-graph-implementation-is-available-on-the-behave-graph-integration-branch-in-the-ethereal-engine-repository",level:3},{value:"2.2 Configuration",id:"22-configuration",level:3},{value:"2.3 Creating your First graph",id:"23-creating-your-first-graph",level:3},{value:"2.3.1 buttons in the graph panel",id:"231-buttons-in-the-graph-panel",level:3},{value:"2.3.2 Saving Graph",id:"232-saving-graph",level:3},{value:"2.3.3 Playing a graph",id:"233-playing-a-graph",level:3},{value:"Ok finally with all this context, lets add a node",id:"ok-finally-with-all-this-context-lets-add-a-node",level:4},{value:"3.2 Key Concepts",id:"32-key-concepts",level:3},{value:"3.3 Engine Nodes",id:"33-engine-nodes",level:3},{value:"3.3.1 Entity",id:"331-entity",level:3},{value:"3.3.2 Component",id:"332-component",level:3},{value:"3.3.3 Engine",id:"333-engine",level:3},{value:"3.3.4 Events",id:"334-events",level:3},{value:"4. Usage",id:"4-usage",level:2},{value:"5.Configuration and Customization",id:"5configuration-and-customization",level:2},{value:"5.1 Making new nodes",id:"51-making-new-nodes",level:3}],h={toc:p},u="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,a.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"introduction"},"Introduction"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Overview"),(0,o.kt)("li",{parentName:"ul"},"Audience")),(0,o.kt)("p",null,"Getting Started"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Installation"),(0,o.kt)("li",{parentName:"ul"},"Configuration")),(0,o.kt)("p",null,"Code Overview:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"High-Level Architecture"),(0,o.kt)("li",{parentName:"ul"},"Key Concepts"),(0,o.kt)("li",{parentName:"ul"},"Engine Nodes")),(0,o.kt)("p",null,"Usage"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Examples")),(0,o.kt)("p",null,"Configuration and Customization"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Making new nodes")),(0,o.kt)("h2",{id:"1-introduction"},"1. Introduction"),(0,o.kt)("h3",{id:"11-overview"},"1.1 Overview"),(0,o.kt)("p",null,"Behavior graphs are expressive, deterministic, and extensible state machines that can encode arbitrarily complex behavior."),(0,o.kt)("p",null,"Behavior graphs are a popular choice for implementing visual scripting languages. Prominent game engines like Unreal Engine and Unity have adopted behavior graphs as an essential component of their visual scripting systems. For example, Unreal Engine's Blueprints, Unity's Visual Scripting, and NVIDIA Omniverse's OmniGraph rely on behavior graphs to enable game designers and developers to create complex behaviors without writing code directly."),(0,o.kt)("p",null,"Within the Ethereal Engine, the Behavior Graphs feature plays a pivotal role by providing a no-code interface to the engine and by interacting with the engine while modeling, organizing, controlling and assigning complex behaviors on entities, with ease."),(0,o.kt)("h3",{id:"12-audience"},"1.2 Audience"),(0,o.kt)("p",null,"Behavior Graphs in the Ethereal engine target developers, designers, artists, and non-technical users. This visual scripting feature enables easy implementation of complex logic and actions for entities without the need for writing scripts. It fosters collaboration and empowers diverse individuals to create immersive experiences and interactive content within the engine."),(0,o.kt)("h2",{id:"2-getting-started"},"2. Getting Started"),(0,o.kt)("h3",{id:"21-installation---at-the-moment-the-behavior-graph-implementation-is-available-on-the-behave-graph-integration-branch-in-the-ethereal-engine-repository"},"2.1 Installation - at the moment the behavior graph implementation is available on the behave-graph-integration branch in the Ethereal Engine Repository"),(0,o.kt)("p",null,"Clone the branch and follow general Ethereal engine installation steps\n",(0,o.kt)("a",{parentName:"p",href:"/docs/host/installation/"},"general instructions")),(0,o.kt)("p",null,"The Behavior Graphs must be defined in the studio and thus require a user to have admin privileges"),(0,o.kt)("h3",{id:"22-configuration"},"2.2 Configuration"),(0,o.kt)("p",null,"The Behave graph is implemented as a component in the engine following the ECS(Entity component system) architecture in the engine."),(0,o.kt)("p",null,"Users can add and remove a behave graph component from an entity "),(0,o.kt)("p",null,"Step 1: find the behave graph component under the scripting section in the component shelf in the right side of the screen\nStep 2:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"double click on the component tor drag and drop into scene to add a new entity with the behave graph component into the screen"),(0,o.kt)("li",{parentName:"ol"},"Drag and drop into the hierarchy panel on another entity to add to scene as child of the selected entity"),(0,o.kt)("li",{parentName:"ol"},"Drag and drop into properties panel of selected entity to add component to entity")),(0,o.kt)("p",null,"The behave graph properties panel has two properties:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Run graph: runs the graph in headless mode as part of the engine"),(0,o.kt)("li",{parentName:"ul"},"Disable graph: disable graph from playing")),(0,o.kt)("h3",{id:"23-creating-your-first-graph"},"2.3 Creating your First graph"),(0,o.kt)("p",null,"Before we dive into creating the graph let's take a look at the graph panel"),(0,o.kt)("p",null,"The graph panel consists of the the panel itself, panel buttons, nodes and connections"),(0,o.kt)("p",null,"The default behave graph consists of an "),(0,o.kt)("p",null,"On start event node"),(0,o.kt)("p",null,"On tick event node"),(0,o.kt)("p",null,"Logger node"),(0,o.kt)("p",null,"To navigate across the panel, drag across the surface of the panel"),(0,o.kt)("h3",{id:"231-buttons-in-the-graph-panel"},"2.3.1 buttons in the graph panel"),(0,o.kt)("p",null,"The buttons panel is location in the bottom left side of the screen"),(0,o.kt)("p",null,"The buttons are as follows"),(0,o.kt)("p",null,"Zoom in: zoom into the graph viewport"),(0,o.kt)("p",null,"Zoom out: zoom out of the graph viewport"),(0,o.kt)("p",null,"Fit view: tries to fit all nodes into the screen at the same time, if not possible it centers the view at the center of all nodes"),(0,o.kt)("p",null,"Lock graph: Toggles ability to graph edit"),(0,o.kt)("p",null,"Help: Opens an instruction modal for making graphs"),(0,o.kt)("p",null,"Load Graph: Opens a modal, user can paste graph json in the input field to load the corresponding graph"),(0,o.kt)("p",null,"Save Graph: Opens a model, user can copy the graph json from the text box and save as needed"),(0,o.kt)("p",null,"Play Graph: runs headful version of the graph connected to the graph editor"),(0,o.kt)("h3",{id:"232-saving-graph"},"2.3.2 Saving Graph"),(0,o.kt)("p",null,"The graph has its own json which is also part of the scene json, therefore the user needs to save the graph in as its own json which then must be saved as a part of the scene"),(0,o.kt)("p",null,"The graph json is autosaved every 5 seconds the graph panel i open and whenever the graph panel is closed (the component unmounts)"),(0,o.kt)("p",null,"The graph and overall changes to the scene must be saved using the save scene option from the main menu"),(0,o.kt)("h3",{id:"233-playing-a-graph"},"2.3.3 Playing a graph"),(0,o.kt)("p",null,"A graph can be played in two modes, headful and headless,"),(0,o.kt)("p",null,"headful mode play - headful mode, activated by pressing the play button in the graph buttons, graph stops executing when the panel is closed or component unmounts, meant for quick testing, setting scene variables and rapid development"),(0,o.kt)("p",null,"Headless mode play - headless mode, play activated from properties panel, execution does not stop unless play is toggled off again from the properties panel"),(0,o.kt)("p",null,"To play all graphs in the scene the user can use the play scene button from the top toolbar"),(0,o.kt)("p",null,"NOTE: headful and headless plays must be managed separately"),(0,o.kt)("h4",{id:"ok-finally-with-all-this-context-lets-add-a-node"},"Ok finally with all this context, lets add a node"),(0,o.kt)("p",null,"To add a node, right click anywhere on the graph panel"),(0,o.kt)("p",null,"This will open up the node picker select window,"),(0,o.kt)("p",null,"Type in the search input to filter nodes by prefix\nClick on the node to add to the panel"),(0,o.kt)("p",null,"Lets add a logger node and connect it to the on tick event"),(0,o.kt)("p",null,"To connect the flow of the nodes , drag from one flow socket to another\nThere can be only one flow output from one flow output socket"),(0,o.kt)("p",null,"But there can be multiple inputs to a flow input socket"),(0,o.kt)("p",null,"To play the graph click on the play graph button"),(0,o.kt)("p",null,"Well done, outputs to the log can be seen in the dev tools console"),(0,o.kt)("p",null,"TODO: add pictures"),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"Code Overview:")),(0,o.kt)("p",null,"Node Types"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Events You can implement arbitrary events that start execution: Start, Tick"),(0,o.kt)("li",{parentName:"ul"},"Actions You can implement actions that trigger animations, scene scene variations, or update internal state: Log, Play Gltf animation, Play Audio, Play Video, etc"),(0,o.kt)("li",{parentName:"ul"},"Logic You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes."),(0,o.kt)("li",{parentName:"ul"},"Queries You can query the state from the system."),(0,o.kt)("li",{parentName:"ul"},"Flow Control Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop"),(0,o.kt)("li",{parentName:"ul"},"Variables You can create, set and get variable values."),(0,o.kt)("li",{parentName:"ul"},"Custom Events You can create, listen to and trigger custom events.")),(0,o.kt)("h3",{id:"32-key-concepts"},"3.2 Key Concepts"),(0,o.kt)("p",null,"Nodes -\nConnections -\nFlow -"),(0,o.kt)("p",null,"Events"),(0,o.kt)("p",null,"Set and Get Scene Properties"),(0,o.kt)("p",null,"Registering nodes"),(0,o.kt)("p",null,"Value Types"),(0,o.kt)("p",null,"Value type Converters"),(0,o.kt)("h3",{id:"33-engine-nodes"},"3.3 Engine Nodes"),(0,o.kt)("h3",{id:"331-entity"},"3.3.1 Entity"),(0,o.kt)("p",null,"Teleport Entity\nAdd Entity\nDelete Entity\nGet Entity from Scene\nGet Camera Entity"),(0,o.kt)("h3",{id:"332-component"},"3.3.2 Component"),(0,o.kt)("p",null,"Add Component"),(0,o.kt)("p",null,"Delete Component"),(0,o.kt)("p",null,"Get component from registry\nGet component from entity"),(0,o.kt)("h3",{id:"333-engine"},"3.3.3 Engine"),(0,o.kt)("p",null,"Play Video"),(0,o.kt)("p",null,"Play Audio"),(0,o.kt)("p",null,"Play Gltf Animations"),(0,o.kt)("p",null,"Get Avatar animations"),(0,o.kt)("p",null,"Fade Camera"),(0,o.kt)("p",null,"Switch Scene"),(0,o.kt)("h3",{id:"334-events"},"3.3.4 Events"),(0,o.kt)("p",null,"Either in pairs of trigger and listener , or just listener\nOn Button State"),(0,o.kt)("p",null,"triggerLoadAsset -> onLoadAsset"),(0,o.kt)("h2",{id:"4-usage"},"4. Usage"),(0,o.kt)("p",null,"Add some example screenshots and explain"),(0,o.kt)("h2",{id:"5configuration-and-customization"},"5.Configuration and Customization"),(0,o.kt)("h3",{id:"51-making-new-nodes"},"5.1 Making new nodes"),(0,o.kt)("p",null,"Describe the creation of nodes"),(0,o.kt)("p",null,"Making flow nodes\nMaking Event node\nMaking Value types"),(0,o.kt)("p",null,"Making Function node"),(0,o.kt)("p",null,"Extending Dependencies"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d7cf77e2.9e856bfc.js b/assets/js/d7cf77e2.9e856bfc.js new file mode 100644 index 000000000000..699ed32440e6 --- /dev/null +++ b/assets/js/d7cf77e2.9e856bfc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[314],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(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<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),d=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=d(e.components);return a.createElement(l.Provider,{value:n},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=d(t),h=r,m=u["".concat(l,".").concat(h)]||u[h]||c[h]||o;return t?a.createElement(m,i(i({ref:n},p),{},{components:t})):a.createElement(m,i({ref:n},p))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,i=new Array(o);i[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var d=2;d<o;d++)i[d]=t[d];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}h.displayName="MDXCreateElement"},7046:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=t(7462),r=(t(7294),t(3905));const o={},i="Advanced Setup",s={unversionedId:"host/installation/advanced_setup",id:"host/installation/advanced_setup",title:"Advanced Setup",description:"If you want to setup Ethereal Engine docker instances, client, server, and/or",source:"@site/docs/1_host/1_installation/4_advanced_setup.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/advanced_setup",permalink:"/etherealengine-docs/docs/host/installation/advanced_setup",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/4_advanced_setup.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing on Windows with WSL2",permalink:"/etherealengine-docs/docs/host/installation/windows_wsl"},next:{title:"Running on Static IP under WSL2",permalink:"/etherealengine-docs/docs/host/installation/running_on_static_IP"}},l={},d=[{value:"1. Install your dependencies",id:"1--install-your-dependencies",level:3},{value:"2. Make sure you have a mysql database installed and running -- our recommendation is Mariadb.",id:"2-make-sure-you-have-a-mysql-database-installed-and-running----our-recommendation-is-mariadb",level:3},{value:"3. Open a new tab and start the Agones sidecar in local mode",id:"3-open-a-new-tab-and-start-the-agones-sidecar-in-local-mode",level:3},{value:"4. Start the server in database seed mode",id:"4-start-the-server-in-database-seed-mode",level:3},{value:"5. Local file server configuration (Optional)",id:"5-local-file-server-configuration-optional",level:3},{value:"6. Open two/three separate tabs and start the API server, instanceserver and client",id:"6-open-twothree-separate-tabs-and-start-the-api-server-instanceserver-and-client",level:3},{value:"7. In a browser, navigate to https://127.0.0.1:3000/location/default",id:"7-in-a-browser-navigate-to-https1270013000locationdefault",level:3}],p={toc:d},u="wrapper";function c(e){let{components:n,...t}=e;return(0,r.kt)(u,(0,a.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"advanced-setup"},"Advanced Setup"),(0,r.kt)("p",null,"If you want to setup Ethereal Engine docker instances, client, server, and/or\ninstance-server manually, follow these directions. The advanced setup is recommended\nfor all users, in order to understand more about everything that's going on."),(0,r.kt)("h3",{id:"1--install-your-dependencies"},"1. Install your dependencies"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd path/to/etherealengine\nnpm install\nnpm run dev-docker\nnpm run dev-reinit\n")),(0,r.kt)("p",null,"You should not need to use sudo in any case."),(0,r.kt)("p",null,"Error with mediasoup? ",(0,r.kt)("a",{parentName:"p",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"https://mediasoup.org/documentation/v3/mediasoup/installation/")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Check your version of python is up to date"),(0,r.kt)("li",{parentName:"ul"},"Ensure your install path has no whitespaces")),(0,r.kt)("h3",{id:"2-make-sure-you-have-a-mysql-database-installed-and-running----our-recommendation-is-mariadb"},"2. Make sure you have a mysql database installed and running -- our recommendation is Mariadb."),(0,r.kt)("p",null,"We've provided a docker container for easy setup:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd scripts && sudo bash start-db.sh\n")),(0,r.kt)("p",null,"This creates a Docker container of mariadb named etherealengine_db. You must have\ndocker installed on your machine for this script to work.\nIf you do not have Docker installed and do not wish to install it, you will have\nto manually create a MariaDB server."),(0,r.kt)("p",null,"The default username is 'server', the default password is 'password', the\ndefault database name is 'etherealengine', the default hostname is '127.0.0.1', and\nthe default port is ",(0,r.kt)("inlineCode",{parentName:"p"},"3306"),"."),(0,r.kt)("p",null,"Seeing errors connecting to the local DB? ",(0,r.kt)("strong",{parentName:"p"},"Try shutting off your local firewall.")),(0,r.kt)("h3",{id:"3-open-a-new-tab-and-start-the-agones-sidecar-in-local-mode"},"3. Open a new tab and start the Agones sidecar in local mode"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd scripts\nsudo bash start-agones.sh\n")),(0,r.kt)("p",null,"You can also go to vendor/agones/ and run"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"./sdk-server.linux.amd64 --local")),(0,r.kt)("p",null,"If you are using a Windows machine, run"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"sdk-server.windows.amd64.exe --local")),(0,r.kt)("p",null,"and for mac, run"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"./sdk-server.darwin.amd64 --local")),(0,r.kt)("h3",{id:"4-start-the-server-in-database-seed-mode"},"4. Start the server in database seed mode"),(0,r.kt)("p",null,"Several tables in the database need to be seeded with default values.\nRun ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-reinit")," or if on windows ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-reinit-windows"),"\nAfter several seconds, there should be no more logging.\nSome of the final lines should read like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"Server Ready\nExecuting (default): SET FOREIGN_KEY_CHECKS = 1\nServer EXIT\n")),(0,r.kt)("p",null,"At this point, the database has been seeded."),(0,r.kt)("h3",{id:"5-local-file-server-configuration-optional"},"5. Local file server configuration (Optional)"),(0,r.kt)("p",null,"If the .env.local file you have has the line\n",(0,r.kt)("inlineCode",{parentName:"p"},"STORAGE_PROVIDER=local"),"\nthen the scene editor will save components, models, scenes, etc. locally\n(as opposed to storing them on S3). You will need to start a local server\nto serve these files, and make sure that .env.local has the line\n",(0,r.kt)("inlineCode",{parentName:"p"},'LOCAL_STORAGE_PROVIDER="localhost:8642"'),".\nIn a new tab, go to ",(0,r.kt)("inlineCode",{parentName:"p"},"packages/server")," and run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run serve-local-files"),".\nThis will start up ",(0,r.kt)("inlineCode",{parentName:"p"},"http-server")," to serve files from ",(0,r.kt)("inlineCode",{parentName:"p"},"packages/server/upload"),"\non ",(0,r.kt)("inlineCode",{parentName:"p"},"localhost:8642"),".\nYou may have to accept the invalid self-signed certificate for it in the browser;\nsee 'Allow local file http-server connection with invalid certificate' below."),(0,r.kt)("h3",{id:"6-open-twothree-separate-tabs-and-start-the-api-server-instanceserver-and-client"},"6. Open two/three separate tabs and start the API server, instanceserver and client"),(0,r.kt)("p",null,"In /packages/server, run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev")," which will launch the api server, world server, media server and file server.\nIf you are not using instanceservers, you can instead run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-api-server")," in the api server.\nIn the final tab, go to /packages/client and run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev"),".\nIf you are on windows you need to use ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-windows")," instead of ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev"),"."),(0,r.kt)("h3",{id:"7-in-a-browser-navigate-to-https1270013000locationdefault"},"7. In a browser, navigate to ",(0,r.kt)("a",{parentName:"h3",href:"https://127.0.0.1:3000/location/default"},"https://127.0.0.1:3000/location/default")),(0,r.kt)("p",null,"The database seeding process creates a default empty location called 'default'.\nIt can be navigated to by going to '",(0,r.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default'"},"https://127.0.0.1:3000/location/default'"),".\nAs of this writing, the cert provided in the ethereal engine package for local use is\nnot adequately signed. You can create signed certificates and replace the\ndefault ones, but most developers just ignore the warnings. Browsers will throw\nup warnings about going to insecure pages. You should be able to tell the browser\nto ignore it, usually by clicking on some sort of 'advanced options' button or\nlink and then something along the lines of 'go there anyway'."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d88112b6.b234a8cf.js b/assets/js/d88112b6.b234a8cf.js new file mode 100644 index 000000000000..36b039a11093 --- /dev/null +++ b/assets/js/d88112b6.b234a8cf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[176],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>b});var r=n(7294);function s(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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){s(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,s=function(e,t){if(null==e)return{};var n,r,s={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var i=r.createContext({}),c=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(i.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,s=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=s,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(b,o(o({ref:t},u),{},{components:n})):r.createElement(b,o({ref:t},u))}));function b(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var a=n.length,o=new Array(a);o[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[p]="string"==typeof e?e:s,o[1]=l;for(var c=2;c<a;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},6792:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(7462),s=(n(7294),n(3905));const a={},o="Cluster Management",l={unversionedId:"host/devops_deployment/managing_remote_kubernetes",id:"host/devops_deployment/managing_remote_kubernetes",title:"Cluster Management",description:"Kubernetes Web UI (Dashboard)",source:"@site/docs/1_host/2_devops_deployment/5_managing_remote_kubernetes.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/managing_remote_kubernetes",permalink:"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/5_managing_remote_kubernetes.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"How to set up GitHub to install external projects",permalink:"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects"},next:{title:"Release Helm Chart",permalink:"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart"}},i={},c=[{value:"Kubernetes Web UI (Dashboard)",id:"kubernetes-web-ui-dashboard",level:2},{value:"Install Lens",id:"install-lens",level:2},{value:"AWS",id:"aws",level:4}],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,s.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"cluster-management"},"Cluster Management"),(0,s.kt)("h2",{id:"kubernetes-web-ui-dashboard"},"Kubernetes Web UI (Dashboard)"),(0,s.kt)("p",null,"Dashboard is a web-based Kubernetes user interface. You can use Dashboard to deploy containerized applications to a Kubernetes cluster, troubleshoot your containerized application, and manage the cluster resources."),(0,s.kt)("p",null,(0,s.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/"},"https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/")),(0,s.kt)("h2",{id:"install-lens"},"Install Lens"),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"sudo snap install kontena-lens --classic")),(0,s.kt)("p",null,"Add the K8 cluster using kubectl\n",(0,s.kt)("a",{parentName:"p",href:"https://docs.k8slens.dev/v4.1.4/clusters/adding-clusters/"},"https://docs.k8slens.dev/v4.1.4/clusters/adding-clusters/")),(0,s.kt)("p",null,"Add kubernetes lens prometheus support if not already installed\n",(0,s.kt)("a",{parentName:"p",href:"https://docs.k8slens.dev/v4.1.4/extensions/usage/"},"https://docs.k8slens.dev/v4.1.4/extensions/usage/")),(0,s.kt)("h4",{id:"aws"},"AWS"),(0,s.kt)("p",null,"AWS credentials with EKS and Cluster permissions required"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dcc1f912.77ac3288.js b/assets/js/dcc1f912.77ac3288.js new file mode 100644 index 000000000000..b3290d913af1 --- /dev/null +++ b/assets/js/dcc1f912.77ac3288.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3666],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var a=n(7294);function l(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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){l(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,l=function(e,t){if(null==e)return{};var n,a,l={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(p.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,l=e.mdxType,r=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=s(n),c=l,h=u["".concat(p,".").concat(c)]||u[c]||m[c]||r;return n?a.createElement(h,i(i({ref:t},d),{},{components:n})):a.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,i=new Array(r);i[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[u]="string"==typeof e?e:l,i[1]=o;for(var s=2;s<r;s++)i[s]=n[s];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},1100:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=n(7462),l=(n(7294),n(3905));const r={},i="Upgrading Helm Release",o={unversionedId:"host/devops_deployment/upgrade_helm_deployment",id:"host/devops_deployment/upgrade_helm_deployment",title:"Upgrading Helm Release",description:"This guide will cover various sections regarding upgrading an existing helm deployment.",source:"@site/docs/1_host/2_devops_deployment/7_upgrade_helm_deployment.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/upgrade_helm_deployment",permalink:"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/7_upgrade_helm_deployment.md",tags:[],version:"current",sidebarPosition:7,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Release Helm Chart",permalink:"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart"},next:{title:"Tutorials",permalink:"/etherealengine-docs/docs/host/devops_deployment/tutorials/"}},p={},s=[{value:"Getting Updated <code>values.yaml</code> File",id:"getting-updated-valuesyaml-file",level:2},{value:"Evaluating Difference in <code>value.yaml</code> & Deployed Charts",id:"evaluating-difference-in-valueyaml--deployed-charts",level:2},{value:"Upgrading Helm Deployment",id:"upgrading-helm-deployment",level:2}],d={toc:s},u="wrapper";function m(e){let{components:t,...n}=e;return(0,l.kt)(u,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"upgrading-helm-release"},"Upgrading Helm Release"),(0,l.kt)("p",null,"This guide will cover various sections regarding upgrading an existing helm deployment."),(0,l.kt)("h2",{id:"getting-updated-valuesyaml-file"},"Getting Updated ",(0,l.kt)("inlineCode",{parentName:"h2"},"values.yaml")," File"),(0,l.kt)("p",null,"Usually a helm release upgrade is required when changes are made in configuration of helm charts. To do so first thing required is ",(0,l.kt)("inlineCode",{parentName:"p"},"value.yaml")," file of current configuration. If you already have an updated copy of this file then you can update the desired values and push the changes to helm deployment."),(0,l.kt)("p",null,"But for scenarios where multiple people are working same deployment, it becomes difficult to maintain updated ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file. At anytime you can get the current version/snapshot of ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file by running ",(0,l.kt)("a",{parentName:"p",href:"https://helm.sh/docs/helm/helm_get_values/"},"get values")," command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm get values [DEPLOYMENT_NAME]\n")),(0,l.kt)("p",null,"i.e."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm get values dev\n")),(0,l.kt)("p",null,"You can save the output in a ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file and update the required values."),(0,l.kt)("h2",{id:"evaluating-difference-in-valueyaml--deployed-charts"},"Evaluating Difference in ",(0,l.kt)("inlineCode",{parentName:"h2"},"value.yaml")," & Deployed Charts"),(0,l.kt)("p",null,"It become very handy if you can evaluate the differences between your local ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file and current deployment. This way you can beforehand visualize the changes a helm upgrade is going to make. To do so first make sure you have ",(0,l.kt)("inlineCode",{parentName:"p"},"helm diff")," plugin installed. You can install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm plugin install https://github.com/databus23/helm-diff\n")),(0,l.kt)("p",null,"Once ",(0,l.kt)("inlineCode",{parentName:"p"},"helm diff")," plugin is installed then you can run following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm diff upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --values [PATH_TO_VALUES_YAML]\n")),(0,l.kt)("p",null,"i.e."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm diff upgrade dev etherealengine/etherealengine --values ~/etherealengine-ops/values/dev.ethereal.values.yaml\n")),(0,l.kt)("p",null,"This will print the output of differences between deployed helm release and changes in specified ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file. Incase the output is empty, it means there is no difference/changes."),(0,l.kt)("h2",{id:"upgrading-helm-deployment"},"Upgrading Helm Deployment"),(0,l.kt)("p",null,"Once the local ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file is updated, it can be reflect to deployment using following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --reuse-values -f [PATH_TO_VALUES_YAML]\n")),(0,l.kt)("p",null,"i.e."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade dev etherealengine/etherealengine --reuse-values -f ~/etherealengine-ops/values/dev.ethereal.values.yaml\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e988a1b0.01f59a3e.js b/assets/js/e988a1b0.01f59a3e.js new file mode 100644 index 000000000000..9eaa5c85007a --- /dev/null +++ b/assets/js/e988a1b0.01f59a3e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4705],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});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 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 l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",h={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,o=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),u=c(n),p=a,m=u["".concat(s,".").concat(p)]||u[p]||h[p]||o;return n?r.createElement(m,l(l({ref:t},d),{},{components:n})):r.createElement(m,l({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=p;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:a,l[1]=i;for(var c=2;c<o;c++)l[c]=n[c];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},9128:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={},l="Old Docker Instructions",i={unversionedId:"host/installation/docker",id:"host/installation/docker",title:"Old Docker Instructions",description:"You can quickstart locally using docker, if you don't have node installed or",source:"@site/docs/1_host/1_installation/7_docker.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/docker",permalink:"/etherealengine-docs/docs/host/installation/docker",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/7_docker.md",tags:[],version:"current",sidebarPosition:7,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Troubleshooting",permalink:"/etherealengine-docs/docs/host/installation/install_troubleshooting"},next:{title:"Logging with Opensearch on Docker",permalink:"/etherealengine-docs/docs/host/installation/opensearch"}},s={},c=[{value:"Get local IP address",id:"get-local-ip-address",level:2},{value:"Start local databases",id:"start-local-databases",level:2},{value:"Build the image",id:"build-the-image",level:2},{value:"Run the server to seed the database, wait a couple minutes, then delete it",id:"run-the-server-to-seed-the-database-wait-a-couple-minutes-then-delete-it",level:2},{value:"Run the images",id:"run-the-images",level:2},{value:"Delete containers, if you want to run a new build, or just get rid of them",id:"delete-containers-if-you-want-to-run-a-new-build-or-just-get-rid-of-them",level:2}],d={toc:c},u="wrapper";function h(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"old-docker-instructions"},"Old Docker Instructions"),(0,a.kt)("p",null,"You can quickstart locally using docker, if you don't have node installed or\njust want to test the latest."),(0,a.kt)("h2",{id:"get-local-ip-address"},"Get local IP address"),(0,a.kt)("p",null,"Use a tool like ",(0,a.kt)("inlineCode",{parentName:"p"},"ifconfig")," to get your local IP address."),(0,a.kt)("h2",{id:"start-local-databases"},"Start local databases"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd scripts\ndocker-compose up\n")),(0,a.kt)("p",null,"When the logging stops, that indicates that the databases have been created and\nare running."),(0,a.kt)("p",null,"Ctrl+c out of that, then from scripts run ",(0,a.kt)("inlineCode",{parentName:"p"},"./start-all-docker.sh"),"\n(This must be run every time you start your machine anew)"),(0,a.kt)("h2",{id:"build-the-image"},"Build the image"),(0,a.kt)("p",null,"Create an empty folder at the root called ",(0,a.kt)("inlineCode",{parentName:"p"},"project-package-jsons")," and then run\nthe following command to build:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'DOCKER_BUILDKIT=1 docker build -t etherealengine --build-arg MYSQL_USER=server \\\n --build-arg MYSQL_PASSWORD=password --build-arg MYSQL_HOST=127.0.0.1 \\\n --build-arg MYSQL_DATABASE=etherealengine --build-arg MYSQL_PORT=3304 \\\n --build-arg VITE_SERVER_HOST=localhost --build-arg VITE_SERVER_PORT=3030 \\\n --build-arg VITE_INSTANCESERVER_HOST=localhost --build-arg VITE_INSTANCESERVER_PORT=3031 \\\n --build-arg VITE_LOCAL_BUILD=true --build-arg CACHE_DATE="$(date)" --network="host" .\n')),(0,a.kt)("h2",{id:"run-the-server-to-seed-the-database-wait-a-couple-minutes-then-delete-it"},"Run the server to seed the database, wait a couple minutes, then delete it"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "FORCE_DB_REFRESH=true" --network host etherealengine\ndocker logs server -f\n-Wait for the line "Server Ready", then Ctrl+c out of the logs-\ndocker container stop server\ndocker container rm server\n')),(0,a.kt)("h2",{id:"run-the-images"},"Run the images"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -d --name serve-local --env-file .env.local.default -e "SERVER_MODE=serve-local" --network host etherealengine\ndocker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine\ndocker run -d --name client --env-file .env.local.default -e "SERVER_MODE=client" --network host etherealengine\ndocker run -d --name world --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine\ndocker run -d --name channel --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" -e "INSTANCESERVER_PORT=3032" --network host etherealengine\n')),(0,a.kt)("h2",{id:"delete-containers-if-you-want-to-run-a-new-build-or-just-get-rid-of-them"},"Delete containers, if you want to run a new build, or just get rid of them"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"docker container stop serve-local\ndocker container rm serve-local\ndocker container stop server\ndocker container rm server\ndocker container stop client\ndocker container rm client\ndocker container stop world\ndocker container rm world\ndocker container stop channel\ndocker container rm channel\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ea08158a.89b4f73b.js b/assets/js/ea08158a.89b4f73b.js new file mode 100644 index 000000000000..cd31bf3d159d --- /dev/null +++ b/assets/js/ea08158a.89b4f73b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4995],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function 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 o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=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):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},h="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),h=p(n),d=i,m=h["".concat(s,".").concat(d)]||h[d]||c[d]||l;return n?a.createElement(m,o(o({ref:t},u),{},{components:n})):a.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,o=new Array(l);o[0]=d;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[h]="string"==typeof e?e:i,o[1]=r;for(var p=2;p<l;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}d.displayName="MDXCreateElement"},4501:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>u});var a=n(7462),i=(n(7294),n(3905)),l=n(4401);const o={},r="Ethereal Engine on Minikube",s={unversionedId:"host/devops_deployment/minikube",id:"host/devops_deployment/minikube",title:"Ethereal Engine on Minikube",description:"Install kubectl, Helm, Docker, and VirtualBox",source:"@site/docs/1_host/2_devops_deployment/1_minikube.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/minikube",permalink:"/etherealengine-docs/docs/host/devops_deployment/minikube",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/1_minikube.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on Docker Desktop",permalink:"/etherealengine-docs/docs/host/devops_deployment/docker_desktop"},next:{title:"Ethereal Engine on AWS",permalink:"/etherealengine-docs/docs/host/devops_deployment/AWS_setup"}},p={},u=[{value:"Install kubectl, Helm, Docker, and VirtualBox",id:"install-kubectl-helm-docker-and-virtualbox",level:2},{value:"Download and install minikube",id:"download-and-install-minikube",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Create minikube cluster",id:"create-minikube-cluster",level:2},{value:"Starting ingress after minikube has started",id:"starting-ingress-after-minikube-has-started",level:3},{value:"Get minikube IP address and edit system hostfile to point to",id:"get-minikube-ip-address-and-edit-system-hostfile-to-point-to",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"Install Elastic Search and Kibana using Helm for Server Logs",id:"install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Run build_minikube.sh",id:"run-build_minikubesh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],h={toc:u},c="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(c,(0,a.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"ethereal-engine-on-minikube"},"Ethereal Engine on Minikube"),(0,i.kt)("h2",{id:"install-kubectl-helm-docker-and-virtualbox"},"Install kubectl, Helm, Docker, and VirtualBox"),(0,i.kt)("p",null,"If ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl"),", ",(0,i.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm"),",\n",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/get-docker/"},"Docker")," and/or ",(0,i.kt)("a",{parentName:"p",href:"https://www.virtualbox.org/wiki/Downloads"},"VirtualBox"),"\naren't already installed on your machine, install them."),(0,i.kt)("p",null,"You may also need to install ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"Docker Compose")),(0,i.kt)("h2",{id:"download-and-install-minikube"},"Download and install minikube"),(0,i.kt)("p",null,"Instructions can be found ",(0,i.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/start/"},"here")),(0,i.kt)("p",null,"While you can follow the demo instructions there about starting minikube, deploying\nsome demo deployments, etc. to get a feel for it, before deploying Ethereal Engine you should delete\nyour minikube cluster, since we have some specific starting requirements."),(0,i.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,i.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local\nservices, you'll need to get the Ethereal Engine repo on your machine. This is most easily\ndone by running ",(0,i.kt)("inlineCode",{parentName:"p"},"git clone https://github.com/etherealengine/etherealengine.git")),(0,i.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,i.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,i.kt)("p",null,"If you run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,i.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,i.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,i.kt)("inlineCode",{parentName:"p"},"./scripts/build_minikube.sh"),"."),(0,i.kt)("h2",{id:"create-minikube-cluster"},"Create minikube cluster"),(0,i.kt)("p",null,"Run the following command:\n",(0,i.kt)("inlineCode",{parentName:"p"},"minikube start --disk-size 40000m --cpus 4 --memory 10124m --addons ingress --driver virtualbox")),(0,i.kt)("p",null,"This says to start minikube with 40GB of disk space, 4 CPUs, 10GB of memory, using VirtualBox as its\ndriver, and starting up an nginx ingress service."),(0,i.kt)("p",null,"The disk space, CPUs, and memory allocation are configurable. These are what we recommend for optimal\nrunning (though the disk space might be a bit more than necessary). When minikube is running,\nit will reserve those resources for itself regardless of whether the services in minikube are using\nthat much."),(0,i.kt)("p",null,"The 10GB of memory might be the spec with the least wiggle room. Later instructions on building\nthe Docker image will have it be built in the minikube context. This uses the RAM reserved for minikube,\nand the client build process normally uses about 8GB of RAM at its peak. minikube may freeze if\nit gets maxed out on RAM, and the Docker build process might freeze indefinitely."),(0,i.kt)("h3",{id:"starting-ingress-after-minikube-has-started"},"Starting ingress after minikube has started"),(0,i.kt)("p",null,"If you forget to use ",(0,i.kt)("inlineCode",{parentName:"p"},"--addons ingress")," when starting minikube, you can start nginx later by\nrunning ",(0,i.kt)("inlineCode",{parentName:"p"},"minikube addons enable ingress")),(0,i.kt)("h2",{id:"get-minikube-ip-address-and-edit-system-hostfile-to-point-to"},"Get minikube IP address and edit system hostfile to point to"),(0,i.kt)("p",null,"Run this command after minikube has started: ",(0,i.kt)("inlineCode",{parentName:"p"},"minikube ip"),"\nThis will get you the address that minikube is running on."),(0,i.kt)("p",null,"You'll need to edit your hostfile to point certain domains to minikube IP addresses. On Linux,\nthis is done by running ",(0,i.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/hosts"),"."),(0,i.kt)("p",null,"Add the following lines:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-conf"},"<Output of 'minikube ip'> local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org\n10.0.2.2 host.minikube.internal\n")),(0,i.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the minikube cluster,\nwhere the nginx ingress server will redirect the traffic to the appropriate pod.\nThe second line is used to give minikube access to your local environment, particularly so that it\ncan access the MariaDB server."),(0,i.kt)("p",null,"Make sure to save this file after you've edited it. On Linux, at least, you need root permissions\nto edit it."),(0,i.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,i.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,i.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,i.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,i.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,i.kt)("p",null,"Make sure that kubectl is pointed at minikube by running ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),",\nwhich should say 'minikube'. You can also run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts\nthat kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,i.kt)("p",null,"Once kubectl is pointed to minikube, from the top of the Ethereal Engine repo, run\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones\nand ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("p",null,"You can run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in minikube. After a minute or so,\nall of these pods should be in the Running state."),(0,i.kt)("h2",{id:"install-elastic-search-and-kibana-using-helm-for-server-logs"},"Install Elastic Search and Kibana using Helm for Server Logs"),(0,i.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,i.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,i.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart: "),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,i.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,i.kt)("p",null,"Now check if the cluster members are up: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,i.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,i.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana")),(0,i.kt)("p",null,"Check if all the pods are ready: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,i.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"http://localhost:5601")," in your browser"),(0,i.kt)("p",null,"In order to connect logger with elasticsearch, update ",(0,i.kt)("inlineCode",{parentName:"p"},"local.minikube.template.values.yaml")," env ",(0,i.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.minikube.template.values.yaml"},"local.minikube.template.values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("h2",{id:"run-build_minikubesh"},"Run build_minikube.sh"),(0,i.kt)("p",null,"When minikube is running, run the following command from the root of the Ethereal Engine repo:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/build_minikube.sh\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,i.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your terminal:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,i.kt)("p",null,"This points Docker ",(0,i.kt)("em",{parentName:"p"},"in the current terminal")," to minikube's Docker environment. Anything that Docker builds\nwill be locally accessible to minikube; if the first main command in the script were not run, Docker would build to your\nmachine's Docker environment, and minikube would not have access to it."),(0,i.kt)("p",null,"The script also builds the full-repo Docker image using several build arguments. Vite, which builds\nthe client files, uses some information from the MariaDB database created for minikube deployments\nto fill in some variables, and needs database credentials. The script will supply default values\nfor all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST,\nVITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your minikube deployment\naccessible on ",(0,i.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different\ndomain, then you'll have to set those three environment variables to what you want them to be (and also\nchange the hostfile records you made pointing those subdomains to minikube's IP)"),(0,i.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for\ndifferent services, it will only run the parts needed for that service. This may take up to 15 minutes,\nthough later builds should take less time as things are cached."),(0,i.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,i.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.minikube.template.values.yaml"},"template")," for this file in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,i.kt)("p",null,"If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable ",(0,i.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. Its mandatory to point to ",(0,i.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,i.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,i.kt)("p",null,"Run the following command: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine"),"."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("p",null,"After a minute or so, running ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api\nservers, and one client server in the Running state. Setting ",(0,i.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers\n(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),".\nThe API pods will restart and will now not attempt to reinit the database on boot."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,i.kt)(l.ZP,{mdxType:"AcceptCertificates"}))}d.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>r});var a=n(7462),i=(n(7294),n(3905));const l={toc:[]},o="wrapper";function r(e){let{components:t,...n}=e;return(0,i.kt)(o,(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,i.kt)("p",null,"Go to ",(0,i.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,i.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,i.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,i.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,i.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}r.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ebc45004.00601ac1.js b/assets/js/ebc45004.00601ac1.js new file mode 100644 index 000000000000..4d5f1ad183a2 --- /dev/null +++ b/assets/js/ebc45004.00601ac1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5194,3179],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),u=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=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=u(n),h=i,m=c["".concat(s,".").concat(h)]||c[h]||p[h]||o;return n?a.createElement(m,r(r({ref:t},d),{},{components:n})):a.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var u=2;u<o;u++)r[u]=n[u];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},8192:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905)),o=n(932);const r={},l="Basic Setup",s={unversionedId:"host/installation/basic_setup",id:"host/installation/basic_setup",title:"Basic Setup",description:"",source:"@site/docs/1_host/1_installation/1_basic_setup.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/basic_setup",permalink:"/etherealengine-docs/docs/host/installation/basic_setup",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/1_basic_setup.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installation",permalink:"/etherealengine-docs/docs/host/installation/"},next:{title:"Installing on Mac OS X",permalink:"/etherealengine-docs/docs/host/installation/mac_os_x"}},u={},d=[],c={toc:d},p="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"basic-setup"},"Basic Setup"),(0,i.kt)(o.default,{mdxType:"Readme"}))}h.isMDXComponent=!0},932:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var a=n(7462),i=(n(7294),n(3905));const o={},r="Installation",l={unversionedId:"host/installation/readme",id:"host/installation/readme",title:"Installation",description:"Getting up and running requires just a few steps, but this can be tricky,",source:"@site/docs/1_host/1_installation/readme.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/",permalink:"/etherealengine-docs/docs/host/installation/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal for Hosts",permalink:"/etherealengine-docs/docs/host/"},next:{title:"Basic Setup",permalink:"/etherealengine-docs/docs/host/installation/basic_setup"}},s={},u=[{value:"Pre-Install Checklist",id:"pre-install-checklist",level:2},{value:"Clone the repository",id:"clone-the-repository",level:3},{value:"Ensure you are running Node 16 or 18",id:"ensure-you-are-running-node-16-or-18",level:3},{value:"Docker is your friend",id:"docker-is-your-friend",level:3},{value:"Quick Start",id:"quick-start",level:2},{value:"Accept Certificates",id:"accept-certificates",level:3},{value:"Admin System and User Setup",id:"admin-system-and-user-setup",level:3},{value:"Alternate Method:",id:"alternate-method",level:4},{value:"Advanced Installation and Troubleshooting",id:"advanced-installation-and-troubleshooting",level:2}],d={toc:u},c="wrapper";function p(e){let{components:t,...o}=e;return(0,i.kt)(c,(0,a.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"installation"},"Installation"),(0,i.kt)("p",null,"Getting up and running requires just a few steps, but this can be tricky,\ndepending on your platform and current environment. Please follow the directions\nfor your environment."),(0,i.kt)("h2",{id:"pre-install-checklist"},"Pre-Install Checklist"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Clone the repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Node.js 16 or 18 (earlier versions not guaranteed to work)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Python >=3.6 + ",(0,i.kt)("a",{parentName:"li",href:"https://pypi.org/project/pip/"},"PIP"),", C++, and\nother build tools. See the ",(0,i.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup install instructions"),"\nfor full details."),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Docker",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"(Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's ",(0,i.kt)("inlineCode",{parentName:"li"},".env.local")," accordingly.")))),(0,i.kt)("p",null,"You should now be ready to follow the ",(0,i.kt)("a",{parentName:"p",href:"#quick-start"},"Quick Start")," instructions."),(0,i.kt)("h3",{id:"clone-the-repository"},"Clone the repository"),(0,i.kt)("p",null,"A lot has changed during development, and our monorepo has gotten quite large.\nTo avoid cloning the entire thing, use this command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"git clone https://github.com/etherealengine/etherealengine --depth 1\n")),(0,i.kt)("h3",{id:"ensure-you-are-running-node-16-or-18"},"Ensure you are running Node 16 or 18"),(0,i.kt)("p",null,"The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions\nare not guaranteed to work properly."),(0,i.kt)("p",null,"A version manager can be helpful for this:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"NodeJS only: ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/nvm-sh/nvm"},"NVM")),(0,i.kt)("li",{parentName:"ul"},"Polyglot: ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/asdf-vm/asdf"},"ASDF"))),(0,i.kt)("p",null,"Before running the engine, please check ",(0,i.kt)("inlineCode",{parentName:"p"},"node --version"),"\nIf you are using a node version below 16, please update or nothing will work.\nYou will know you are having issues if you try to install at root and are\ngetting dependency errors."),(0,i.kt)("h3",{id:"docker-is-your-friend"},"Docker is your friend"),(0,i.kt)("p",null,"You don't need to use ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/"},"Docker"),", but it will make\nyour life much easier.\nIf you don't wish to use Docker, you will need to setup mariadb and redis on\nyour machine. You can find credentials in ",(0,i.kt)("inlineCode",{parentName:"p"},"/scripts/docker-compose.yml")),(0,i.kt)("h2",{id:"quick-start"},"Quick Start"),(0,i.kt)("p",null,"If you are lucky, this will just work. However, you may encounter some\nissues. Make sure you are running Node 16, and check your dependencies."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd path/to/etherealengine\ncp .env.local.default .env.local\nnpm install\nnpm run dev-docker\nnpm run dev-reinit\nnpm run dev\n")),(0,i.kt)("p",null,"Now run Ethereal Engine in browser by navigating to ",(0,i.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default"},"this link"),". "),(0,i.kt)("h3",{id:"accept-certificates"},"Accept Certificates"),(0,i.kt)("p",null,"You'll have to tell your browser to ignore the insecure connections when you try to load the website."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates."),(0,i.kt)("li",{parentName:"ol"},"Open Developer tools in your browser by clicking the side menu with three dots, then ",(0,i.kt)("inlineCode",{parentName:"li"},"More tools > Developer tools")," (or use ",(0,i.kt)("inlineCode",{parentName:"li"},"Ctrl+Shift+I"),") and then go to the 'Console' tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.")),(0,i.kt)("h3",{id:"admin-system-and-user-setup"},"Admin System and User Setup"),(0,i.kt)("p",null,"You can administrate many features from the admin panel at https://localhost:3000/admin"),(0,i.kt)("p",null,"To make a user an admin, open a page and open the profile menu. There is a button labelled ",(0,i.kt)("inlineCode",{parentName:"p"},"Show User ID"),"\nwhich opens a text field with your userId. Paste it in and run the following command in\nyour terminal:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id={COPIED_USER_ID}")),(0,i.kt)("p",null,"Example:\n",(0,i.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac")),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"image",src:n(2288).Z,width:"596",height:"294"})),(0,i.kt)("h4",{id:"alternate-method"},"Alternate Method:"),(0,i.kt)("p",null,"Look up in User table and change userRole to 'admin'\n(It helps to use a graphical database explorer, we recommend ",(0,i.kt)("a",{parentName:"p",href:"https://beekeeperstudio.io/"},"beekeeperstudio.io"),")"),(0,i.kt)("p",null,"Test user Admin privileges by going to ",(0,i.kt)("inlineCode",{parentName:"p"},"/admin")),(0,i.kt)("h2",{id:"advanced-installation-and-troubleshooting"},"Advanced Installation and Troubleshooting"),(0,i.kt)("p",null,"If you run into any trouble with the Quick Start instructions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Please make sure you've followed the\n",(0,i.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup installation instructions")),(0,i.kt)("li",{parentName:"ul"},"Check your OS-specific instructions:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/windows"},"Installing on Windows (10+)")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/mac_os_x"},"Installing on Mac OS X")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/install_troubleshooting"},"Installation Troubleshooting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/advanced_setup"},"Advanced Setup")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://vitejs.dev/guide/troubleshooting.html#dev-server"},"Vite dev server is stalling"))))}p.isMDXComponent=!0},2288:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png"}}]); \ No newline at end of file diff --git a/assets/js/f7429bc1.99a5afc2.js b/assets/js/f7429bc1.99a5afc2.js new file mode 100644 index 000000000000..a8736230b765 --- /dev/null +++ b/assets/js/f7429bc1.99a5afc2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3179],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=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},d=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=u(n),h=r,m=p["".concat(s,".").concat(h)]||p[h]||c[h]||i;return n?a.createElement(m,o(o({ref:t},d),{},{components:n})):a.createElement(m,o({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var u=2;u<i;u++)o[u]=n[u];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},932:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(7462),r=(n(7294),n(3905));const i={},o="Installation",l={unversionedId:"host/installation/readme",id:"host/installation/readme",title:"Installation",description:"Getting up and running requires just a few steps, but this can be tricky,",source:"@site/docs/1_host/1_installation/readme.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/",permalink:"/etherealengine-docs/docs/host/installation/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal for Hosts",permalink:"/etherealengine-docs/docs/host/"},next:{title:"Basic Setup",permalink:"/etherealengine-docs/docs/host/installation/basic_setup"}},s={},u=[{value:"Pre-Install Checklist",id:"pre-install-checklist",level:2},{value:"Clone the repository",id:"clone-the-repository",level:3},{value:"Ensure you are running Node 16 or 18",id:"ensure-you-are-running-node-16-or-18",level:3},{value:"Docker is your friend",id:"docker-is-your-friend",level:3},{value:"Quick Start",id:"quick-start",level:2},{value:"Accept Certificates",id:"accept-certificates",level:3},{value:"Admin System and User Setup",id:"admin-system-and-user-setup",level:3},{value:"Alternate Method:",id:"alternate-method",level:4},{value:"Advanced Installation and Troubleshooting",id:"advanced-installation-and-troubleshooting",level:2}],d={toc:u},p="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(p,(0,a.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"installation"},"Installation"),(0,r.kt)("p",null,"Getting up and running requires just a few steps, but this can be tricky,\ndepending on your platform and current environment. Please follow the directions\nfor your environment."),(0,r.kt)("h2",{id:"pre-install-checklist"},"Pre-Install Checklist"),(0,r.kt)("ul",{className:"contains-task-list"},(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less"),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Clone the repository"),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Node.js 16 or 18 (earlier versions not guaranteed to work)"),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Python >=3.6 + ",(0,r.kt)("a",{parentName:"li",href:"https://pypi.org/project/pip/"},"PIP"),", C++, and\nother build tools. See the ",(0,r.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup install instructions"),"\nfor full details."),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Docker",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"(Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's ",(0,r.kt)("inlineCode",{parentName:"li"},".env.local")," accordingly.")))),(0,r.kt)("p",null,"You should now be ready to follow the ",(0,r.kt)("a",{parentName:"p",href:"#quick-start"},"Quick Start")," instructions."),(0,r.kt)("h3",{id:"clone-the-repository"},"Clone the repository"),(0,r.kt)("p",null,"A lot has changed during development, and our monorepo has gotten quite large.\nTo avoid cloning the entire thing, use this command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"git clone https://github.com/etherealengine/etherealengine --depth 1\n")),(0,r.kt)("h3",{id:"ensure-you-are-running-node-16-or-18"},"Ensure you are running Node 16 or 18"),(0,r.kt)("p",null,"The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions\nare not guaranteed to work properly."),(0,r.kt)("p",null,"A version manager can be helpful for this:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"NodeJS only: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/nvm-sh/nvm"},"NVM")),(0,r.kt)("li",{parentName:"ul"},"Polyglot: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/asdf-vm/asdf"},"ASDF"))),(0,r.kt)("p",null,"Before running the engine, please check ",(0,r.kt)("inlineCode",{parentName:"p"},"node --version"),"\nIf you are using a node version below 16, please update or nothing will work.\nYou will know you are having issues if you try to install at root and are\ngetting dependency errors."),(0,r.kt)("h3",{id:"docker-is-your-friend"},"Docker is your friend"),(0,r.kt)("p",null,"You don't need to use ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/"},"Docker"),", but it will make\nyour life much easier.\nIf you don't wish to use Docker, you will need to setup mariadb and redis on\nyour machine. You can find credentials in ",(0,r.kt)("inlineCode",{parentName:"p"},"/scripts/docker-compose.yml")),(0,r.kt)("h2",{id:"quick-start"},"Quick Start"),(0,r.kt)("p",null,"If you are lucky, this will just work. However, you may encounter some\nissues. Make sure you are running Node 16, and check your dependencies."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd path/to/etherealengine\ncp .env.local.default .env.local\nnpm install\nnpm run dev-docker\nnpm run dev-reinit\nnpm run dev\n")),(0,r.kt)("p",null,"Now run Ethereal Engine in browser by navigating to ",(0,r.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default"},"this link"),". "),(0,r.kt)("h3",{id:"accept-certificates"},"Accept Certificates"),(0,r.kt)("p",null,"You'll have to tell your browser to ignore the insecure connections when you try to load the website."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates."),(0,r.kt)("li",{parentName:"ol"},"Open Developer tools in your browser by clicking the side menu with three dots, then ",(0,r.kt)("inlineCode",{parentName:"li"},"More tools > Developer tools")," (or use ",(0,r.kt)("inlineCode",{parentName:"li"},"Ctrl+Shift+I"),") and then go to the 'Console' tab."),(0,r.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab."),(0,r.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.")),(0,r.kt)("h3",{id:"admin-system-and-user-setup"},"Admin System and User Setup"),(0,r.kt)("p",null,"You can administrate many features from the admin panel at https://localhost:3000/admin"),(0,r.kt)("p",null,"To make a user an admin, open a page and open the profile menu. There is a button labelled ",(0,r.kt)("inlineCode",{parentName:"p"},"Show User ID"),"\nwhich opens a text field with your userId. Paste it in and run the following command in\nyour terminal:"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id={COPIED_USER_ID}")),(0,r.kt)("p",null,"Example:\n",(0,r.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac")),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"image",src:n(2288).Z,width:"596",height:"294"})),(0,r.kt)("h4",{id:"alternate-method"},"Alternate Method:"),(0,r.kt)("p",null,"Look up in User table and change userRole to 'admin'\n(It helps to use a graphical database explorer, we recommend ",(0,r.kt)("a",{parentName:"p",href:"https://beekeeperstudio.io/"},"beekeeperstudio.io"),")"),(0,r.kt)("p",null,"Test user Admin privileges by going to ",(0,r.kt)("inlineCode",{parentName:"p"},"/admin")),(0,r.kt)("h2",{id:"advanced-installation-and-troubleshooting"},"Advanced Installation and Troubleshooting"),(0,r.kt)("p",null,"If you run into any trouble with the Quick Start instructions:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Please make sure you've followed the\n",(0,r.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup installation instructions")),(0,r.kt)("li",{parentName:"ul"},"Check your OS-specific instructions:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/windows"},"Installing on Windows (10+)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/mac_os_x"},"Installing on Mac OS X")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/install_troubleshooting"},"Installation Troubleshooting")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/docs/host/installation/advanced_setup"},"Advanced Setup")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://vitejs.dev/guide/troubleshooting.html#dev-server"},"Vite dev server is stalling"))))}c.isMDXComponent=!0},2288:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png"}}]); \ No newline at end of file diff --git a/assets/js/fc66d9af.b31bd970.js b/assets/js/fc66d9af.b31bd970.js new file mode 100644 index 000000000000..b365272c93cf --- /dev/null +++ b/assets/js/fc66d9af.b31bd970.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3113],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var a=r(7294);function n(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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},o=Object.keys(e);for(a=0;a<o.length;a++)r=o[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)r=o[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),c=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),h=c(r),u=n,m=h["".concat(l,".").concat(u)]||h[u]||d[u]||o;return r?a.createElement(m,i(i({ref:t},p),{},{components:r})):a.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=u;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,i[1]=s;for(var c=2;c<o;c++)i[c]=r[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,r)}u.displayName="MDXCreateElement"},1944:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=r(7462),n=(r(7294),r(3905));const o={id:"overview",title:"Overview",sidebar_label:"Overview",slug:"/",sidebar_position:0},i="Ethereal Engine",s={unversionedId:"overview",id:"overview",title:"Overview",description:"Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for",source:"@site/docs/0_start_here.md",sourceDirName:".",slug:"/",permalink:"/etherealengine-docs/docs/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/0_start_here.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{id:"overview",title:"Overview",sidebar_label:"Overview",slug:"/",sidebar_position:0},sidebar:"tutorialSidebar",next:{title:"Ethereal for Hosts",permalink:"/etherealengine-docs/docs/host/"}},l={},c=[{value:"WebXR Engine",id:"webxr-engine",level:2},{value:"On The Web",id:"on-the-web",level:2},{value:"Deployment Stack",id:"deployment-stack",level:2},{value:"Ethereal Studio",id:"ethereal-studio",level:2},{value:"Project API",id:"project-api",level:2},{value:"Stack Overview",id:"stack-overview",level:2}],p={toc:c},h="wrapper";function d(e){let{components:t,...o}=e;return(0,n.kt)(h,(0,a.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"ethereal-engine"},"Ethereal Engine"),(0,n.kt)("p",null,"Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for\nany reason - to host events, make games, showcase art, or just to provide a space for your community. There are plenty of platforms on which you can spend a bit to have a world, but you can't be in complete control of the experience or customise it from the ground up."),(0,n.kt)("p",null,"When the Ethereal Engine stack is deployed, that stack is sovereign, open and cross\nplatform by default. Users can create any kind of game or experience with no limits.\nWith the tech that's being built now, users will be able to seamlessly travel\nthrough portals from any worlds to any other world, on different servers, and have all\ntheir data and identity travel with them."),(0,n.kt)("p",null,"This technology is for everyone, but especially people who want to build or\nbelong to a community."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(1769).Z,width:"1600",height:"900"})),(0,n.kt)("h2",{id:"webxr-engine"},"WebXR Engine"),(0,n.kt)("p",null,"The core engine is the heart of Ethereal Engine. Based around the WebXR spec, brought to life with libraries such as ",(0,n.kt)("a",{parentName:"p",href:"https://threejs.org/"},"threejs"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/NateTheGreatt/bitECS"},"bitecs"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/dimforge/rapier.js"},"rapier.js"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/versatica/mediasoup"},"Mediasoup WebRTC"),", ",(0,n.kt)("a",{parentName:"p",href:"https://reactjs.org/"},"reactjs")," & ",(0,n.kt)("a",{parentName:"p",href:"https://hookstate.js.org/"},"hookstatejs"),". With the latest understanding of Data-Oriented Design, ECS and Event-Sourcing paradigms, we have put together a robust MMO XR framework that rivals AAA capabilities, quality and speed."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(9737).Z,width:"3402",height:"1695"})),(0,n.kt)("h2",{id:"on-the-web"},"On The Web"),(0,n.kt)("p",null,"Built for the web, Ethereal Engine providers a fully customisable and clean UI that works in both immersive and non-immersive contexts, as well as an administration panel for full control of deployment, locations, projects, avatars, custom routes & more."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(7204).Z,width:"1586",height:"884"})),(0,n.kt)("h2",{id:"deployment-stack"},"Deployment Stack"),(0,n.kt)("p",null,"Running on the backend is a state of the art fullstack framework, template & deployment pipeline using ",(0,n.kt)("a",{parentName:"p",href:"https://kubernetes.io/"},"kubernetes"),", ",(0,n.kt)("a",{parentName:"p",href:"https://www.docker.com/"},"docker"),", ",(0,n.kt)("a",{parentName:"p",href:"https://agones.dev/site/"},"agones"),", ",(0,n.kt)("a",{parentName:"p",href:"https://open-match.dev/site/"},"openmatch")," & ",(0,n.kt)("a",{parentName:"p",href:"https://feathersjs.com/"},"feathersjs"),". The result is a fully customisable and scalable web app."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(9468).Z,width:"1068",height:"731"})),(0,n.kt)("h2",{id:"ethereal-studio"},"Ethereal Studio"),(0,n.kt)("p",null,"The Studio sits on top of the engine, as a heavily modified version of ",(0,n.kt)("a",{parentName:"p",href:"https://hubs.mozilla.com/spoke"},"Mozilla Hubs' Spoke editor"),". It has been transformed with the engine and the web app to provide a fast and comprehensive Content Management System, file browser, cloud edge caching, content pipeline tools and other creator tools."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(6711).Z,width:"1080",height:"608"})),(0,n.kt)("h2",{id:"project-api"},"Project API"),(0,n.kt)("p",null,"The Project API is the core of what makes Ethereal Engine shine - the ability to load your own scenes, assets & code with a click of a button. Using github, we allow users to have fully version controlled access to extend the base functionality. You can see examples of the Project API in action ",(0,n.kt)("a",{parentName:"p",href:"https://etherealengine.com/explore"},"here")," and ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ee-development-test-suite"},"here")),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(745).Z,width:"789",height:"404"})),(0,n.kt)("h2",{id:"stack-overview"},"Stack Overview"),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(4724).Z,width:"653",height:"977"})))}d.isMDXComponent=!0},7204:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg"},9468:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg"},1769:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg"},745:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg"},6711:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg"},4724:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png"},9737:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg"}}]); \ No newline at end of file diff --git a/assets/js/main.a156226e.js b/assets/js/main.a156226e.js new file mode 100644 index 000000000000..7131aa5625ac --- /dev/null +++ b/assets/js/main.a156226e.js @@ -0,0 +1,2 @@ +/*! For license information please see main.a156226e.js.LICENSE.txt */ +(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[179],{830:(e,t,n)=>{"use strict";n.d(t,{W:()=>a});var r=n(7294);function a(){return r.createElement("svg",{width:"20",height:"20",className:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},r.createElement("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}},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={"0304d7f4":[()=>n.e(8953).then(n.bind(n,8359)),"@site/docs/2_creator/4_development/3_networking.md",8359],"0346e14a":[()=>n.e(720).then(n.bind(n,7887)),"@site/docs/1_host/2_devops_deployment/2_installing_projects.md",7887],"06bf4b13":[()=>n.e(5572).then(n.bind(n,8050)),"@site/docs/1_host/1_installation/8_opensearch.md",8050],"0991b023":[()=>n.e(6524).then(n.bind(n,8778)),"@site/docs/2_creator/1_concepts/readme.md",8778],"0f5dde8f":[()=>n.e(3976).then(n.bind(n,1868)),"@site/docs/1_host/3_Admin_Dashboard/readme.md",1868],"12905b1d":[()=>n.e(2345).then(n.bind(n,3686)),"@site/docs/1_host/2_devops_deployment/4_setup_github_oauth_for_projects.md",3686],"14d2cd64":[()=>n.e(2901).then(n.bind(n,3219)),"@site/docs/2_creator/4_development/1_state_management.md",3219],"15dae980":[()=>n.e(1489).then(n.bind(n,8453)),"@site/docs/1_host/1_installation/3_windows_wsl.md",8453],17896441:[()=>Promise.all([n.e(3312),n.e(272),n.e(7918)]).then(n.bind(n,903)),"@theme/DocItem",903],"1a4e3797":[()=>Promise.all([n.e(3312),n.e(7920)]).then(n.bind(n,6675)),"@theme/SearchPage",6675],"1be78505":[()=>Promise.all([n.e(3312),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1df93b7f":[()=>Promise.all([n.e(3312),n.e(3237)]).then(n.bind(n,3808)),"@site/src/pages/index.tsx",3808],"1f391b9e":[()=>Promise.all([n.e(3312),n.e(272),n.e(3085)]).then(n.bind(n,4247)),"@theme/MDXPage",4247],"222ee964":[()=>n.e(401).then(n.t.bind(n,3769,19)),"/home/runner/work/etherealengine/etherealengine/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],24869598:[()=>n.e(3573).then(n.bind(n,8170)),"@site/docs/1_host/2_devops_deployment/6_release_helm_chart.md",8170],"271238cb":[()=>n.e(5003).then(n.bind(n,1468)),"@site/docs/2_creator/6_testing/5_debugging_device_wsl.md",1468],"28d03809":[()=>n.e(1423).then(n.bind(n,3030)),"@site/docs/2_creator/2_studio/readme.md",3030],"291a898d":[()=>n.e(2606).then(n.bind(n,9871)),"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/readme.md",9871],"33e7527e":[()=>n.e(2984).then(n.t.bind(n,7085,19)),"/home/runner/work/etherealengine/etherealengine/docs/.docusaurus/docusaurus-theme-search-algolia/default/plugin-route-context-module-100.json",7085],"393be207":[()=>n.e(7414).then(n.bind(n,3123)),"@site/src/pages/markdown-page.md",3123],"3c3cda30":[()=>n.e(9037).then(n.bind(n,7360)),"@site/docs/1_host/2_devops_deployment/0_microk8s_windows.md",7360],"3ec03ade":[()=>n.e(6916).then(n.bind(n,5545)),"@site/docs/1_host/1_installation/5_running_on_static_IP.md",5545],"46dcad74":[()=>n.e(5520).then(n.bind(n,6506)),"@site/docs/1_host/1_installation/6_install_troubleshooting.md",6506],47408852:[()=>n.e(2130).then(n.bind(n,496)),"@site/docs/2_creator/6_testing/readme.md",496],"4a109b8c":[()=>n.e(943).then(n.bind(n,8960)),"@site/docs/2_creator/4_development/0_projects_overview.md",8960],"4a62c6ed":[()=>n.e(5624).then(n.bind(n,8510)),"@site/docs/2_creator/4_development/readme.md",8510],"4b422948":[()=>n.e(3881).then(n.bind(n,3825)),"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/01_getting_started.md",3825],"4c80fdcb":[()=>n.e(8511).then(n.bind(n,4155)),"@site/docs/2_creator/5_tutorials/1_ethereal_engine/readme.md",4155],"530a89a7":[()=>n.e(5111).then(n.bind(n,1869)),"@site/docs/2_creator/5_tutorials/1_ethereal_engine/01_unity_bridge.md",1869],"54e37525":[()=>n.e(6718).then(n.bind(n,5888)),"@site/docs/2_creator/6_testing/2_reasonable_code.md",5888],58222842:[()=>n.e(8718).then(n.bind(n,765)),"@site/docs/1_host/2_devops_deployment/2_AWS_setup.md",765],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"6807199d":[()=>n.e(301).then(n.bind(n,6364)),"@site/docs/2_creator/7_avatars/readme.md",6364],75750052:[()=>n.e(532).then(n.bind(n,2510)),"@site/docs/2_creator/6_testing/4_debugging.md",2510],"82399a21":[()=>n.e(1473).then(n.bind(n,8993)),"@site/docs/2_creator/5_tutorials/1_ethereal_engine/02_unreal_bridge.md",8993],"86c50ec3":[()=>n.e(8625).then(n.bind(n,183)),"@site/docs/1_host/1_installation/2_mac_os_x.md",183],"8df89772":[()=>n.e(8620).then(n.bind(n,4085)),"@site/docs/2_creator/3_importing_assets/readme.md",4085],"917fb754":[()=>n.e(7053).then(n.bind(n,2018)),"@site/docs/2_creator/5_tutorials/readme.md",2018],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"95bfc3a6":[()=>n.e(5459).then(n.bind(n,9702)),"@site/docs/1_host/2_devops_deployment/8_tutorials/readme.md",9702],"9a2a3fee":[()=>n.e(5229).then(n.bind(n,3901)),"@site/docs/1_host/2_devops_deployment/3_database_migrations.md",3901],a1c60d7a:[()=>n.e(8949).then(n.bind(n,1144)),"@site/docs/3_guest/readme.md",1144],a47a1e93:[()=>n.e(5992).then(n.bind(n,7878)),"@site/docs/2_creator/6_testing/1_testing_intro.md",7878],a91c512d:[()=>n.e(4449).then(n.bind(n,6793)),"@site/docs/1_host/2_devops_deployment/1_docker_desktop.md",6793],b04e8f41:[()=>n.e(2142).then(n.bind(n,1173)),"@site/docs/2_creator/1_concepts/1_editor_scenes_locations.md",1173],b5eb9e9a:[()=>n.e(6658).then(n.bind(n,7157)),"@site/docs/1_host/1_installation/3_windows.md",7157],b68e3f8b:[()=>n.e(543).then(n.bind(n,450)),"@site/docs/1_host/2_devops_deployment/readme.md",450],bddbf10d:[()=>n.e(8823).then(n.bind(n,2401)),"@site/docs/1_host/readme.md",2401],c538f40f:[()=>n.e(3850).then(n.bind(n,8580)),"@site/docs/2_creator/readme.md",8580],c7af7f81:[()=>n.e(4380).then(n.bind(n,6030)),"@site/docs/1_host/2_devops_deployment/0_microk8s_linux.md",6030],cc938c89:[()=>n.e(3709).then(n.bind(n,4458)),"@site/docs/2_creator/6_testing/3_test_driven_development.md",4458],cf339e2e:[()=>n.e(4438).then(n.t.bind(n,5745,19)),"/home/runner/work/etherealengine/etherealengine/docs/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],d05402c5:[()=>n.e(6970).then(n.bind(n,6064)),"@site/docs/2_creator/4_development/4_actions_event_sourcing.md",6064],d43455fa:[()=>n.e(1205).then(n.bind(n,9347)),"@site/docs/2_creator/4_development/2_ecs.md",9347],d50cf8bd:[()=>n.e(1364).then(n.bind(n,9466)),"@site/docs/2_creator/6_testing/6_debugging_deployed_instanceservers.md",9466],d519f5a1:[()=>n.e(5046).then(n.bind(n,806)),"@site/docs/2_creator/4_development/5_behave_graph.md",806],d7cf77e2:[()=>n.e(314).then(n.bind(n,7046)),"@site/docs/1_host/1_installation/4_advanced_setup.md",7046],d88112b6:[()=>n.e(176).then(n.bind(n,6792)),"@site/docs/1_host/2_devops_deployment/5_managing_remote_kubernetes.md",6792],dcc1f912:[()=>n.e(3666).then(n.bind(n,1100)),"@site/docs/1_host/2_devops_deployment/7_upgrade_helm_deployment.md",1100],e988a1b0:[()=>n.e(4705).then(n.bind(n,9128)),"@site/docs/1_host/1_installation/7_docker.md",9128],ea08158a:[()=>n.e(4995).then(n.bind(n,4501)),"@site/docs/1_host/2_devops_deployment/1_minikube.md",4501],ebc45004:[()=>n.e(5194).then(n.bind(n,8192)),"@site/docs/1_host/1_installation/1_basic_setup.md",8192],f7429bc1:[()=>n.e(3179).then(n.bind(n,932)),"@site/docs/1_host/1_installation/readme.md",932],fc66d9af:[()=>n.e(3113).then(n.bind(n,1944)),"@site/docs/0_start_here.md",1944]};function c(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 u=n(9670),d=n(226);function p(e,t){if("*"===e)return i()({loading:c,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=[],h=(0,u.Z)(o);return Object.entries(h).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:c,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:"/etherealengine-docs/markdown-page",component:p("/etherealengine-docs/markdown-page","d17"),exact:!0},{path:"/etherealengine-docs/search",component:p("/etherealengine-docs/search","fe4"),exact:!0},{path:"/etherealengine-docs/docs",component:p("/etherealengine-docs/docs","376"),routes:[{path:"/etherealengine-docs/docs/",component:p("/etherealengine-docs/docs/","84b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/",component:p("/etherealengine-docs/docs/creator/","c0c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/avatars/",component:p("/etherealengine-docs/docs/creator/avatars/","e46"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/concepts/",component:p("/etherealengine-docs/docs/creator/concepts/","261"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations",component:p("/etherealengine-docs/docs/creator/concepts/editor_scenes_locations","687"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/",component:p("/etherealengine-docs/docs/creator/development/","a0f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/actions_event_sourcing",component:p("/etherealengine-docs/docs/creator/development/actions_event_sourcing","07b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/behave_graph",component:p("/etherealengine-docs/docs/creator/development/behave_graph","f1b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/ecs",component:p("/etherealengine-docs/docs/creator/development/ecs","2d7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/networking",component:p("/etherealengine-docs/docs/creator/development/networking","d32"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/projects_overview",component:p("/etherealengine-docs/docs/creator/development/projects_overview","ebc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/development/state_management",component:p("/etherealengine-docs/docs/creator/development/state_management","e64"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/importing_assets/",component:p("/etherealengine-docs/docs/creator/importing_assets/","7b2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/studio/",component:p("/etherealengine-docs/docs/creator/studio/","796"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/",component:p("/etherealengine-docs/docs/creator/testing/","cf6"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/debugging",component:p("/etherealengine-docs/docs/creator/testing/debugging","b7c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers",component:p("/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers","c39"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/debugging_device_wsl",component:p("/etherealengine-docs/docs/creator/testing/debugging_device_wsl","829"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/reasonable_code",component:p("/etherealengine-docs/docs/creator/testing/reasonable_code","360"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/test_driven_development",component:p("/etherealengine-docs/docs/creator/testing/test_driven_development","0d2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/testing/testing_intro",component:p("/etherealengine-docs/docs/creator/testing/testing_intro","efe"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/tutorials/",component:p("/etherealengine-docs/docs/creator/tutorials/","b8d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/",component:p("/etherealengine-docs/docs/creator/tutorials/ethereal_engine/","1dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge",component:p("/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge","a34"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge",component:p("/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge","cd2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/guest/",component:p("/etherealengine-docs/docs/guest/","f3a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/",component:p("/etherealengine-docs/docs/host/","3a2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/Admin_Dashboard/",component:p("/etherealengine-docs/docs/host/Admin_Dashboard/","258"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/",component:p("/etherealengine-docs/docs/host/devops_deployment/","30b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/AWS_setup",component:p("/etherealengine-docs/docs/host/devops_deployment/AWS_setup","3ef"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/database_migrations",component:p("/etherealengine-docs/docs/host/devops_deployment/database_migrations","7e5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/docker_desktop",component:p("/etherealengine-docs/docs/host/devops_deployment/docker_desktop","8e1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/installing_projects",component:p("/etherealengine-docs/docs/host/devops_deployment/installing_projects","f48"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes",component:p("/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes","226"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux",component:p("/etherealengine-docs/docs/host/devops_deployment/microk8s_linux","6ab"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows",component:p("/etherealengine-docs/docs/host/devops_deployment/microk8s_windows","7ec"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/minikube",component:p("/etherealengine-docs/docs/host/devops_deployment/minikube","ac8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart",component:p("/etherealengine-docs/docs/host/devops_deployment/release_helm_chart","e29"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects",component:p("/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects","d72"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/tutorials/",component:p("/etherealengine-docs/docs/host/devops_deployment/tutorials/","8ef"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/",component:p("/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/","997"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started",component:p("/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started","ab4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment",component:p("/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment","169"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/",component:p("/etherealengine-docs/docs/host/installation/","0f0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/advanced_setup",component:p("/etherealengine-docs/docs/host/installation/advanced_setup","81c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/basic_setup",component:p("/etherealengine-docs/docs/host/installation/basic_setup","eea"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/docker",component:p("/etherealengine-docs/docs/host/installation/docker","706"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/install_troubleshooting",component:p("/etherealengine-docs/docs/host/installation/install_troubleshooting","105"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/mac_os_x",component:p("/etherealengine-docs/docs/host/installation/mac_os_x","1bf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/opensearch",component:p("/etherealengine-docs/docs/host/installation/opensearch","589"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/running_on_static_IP",component:p("/etherealengine-docs/docs/host/installation/running_on_static_IP","04e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/windows",component:p("/etherealengine-docs/docs/host/installation/windows","cc4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/docs/host/installation/windows_wsl",component:p("/etherealengine-docs/docs/host/installation/windows_wsl","47d"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/etherealengine-docs/",component:p("/etherealengine-docs/","21d"),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 c=n(723),u=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),h=n(2263),g=n(4996),b=n(6668),v=n(833),y=n(4711),w=n(9727),k=n(3320),_=n(197);function E(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,h.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 S(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,h.Z)(),a=function(){const{siteConfig:{url:e}}=(0,h.Z)(),{pathname:t}=(0,u.TH)();return e+(0,g.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 x(){const{i18n:{currentLocale:e}}=(0,h.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(S,null),r.createElement(E,null),r.createElement(_.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)(c.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 R(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=s.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const P=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),R("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)(c.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?R("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=R("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(P,{previousLocation:this.previousLocation,location:t},r.createElement(u.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<div id="${M}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${F}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${F}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function z(){const{siteConfig:{baseUrl:e}}=(0,h.Z)();return(0,r.useLayoutEffect)((()=>{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,h.Z)(),{pathname:n}=(0,u.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,h.Z)(),i=(0,g.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 H(){const e=(0,d.H)(c.Z),t=(0,u.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(x,null),r.createElement(U,null),r.createElement(I,{location:T(t)},e)))))}var G=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,K=new Set,Y=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Q={prefetch(e){if(!(e=>!Y()&&!K.has(e)&&!W.has(e))(e))return!1;W.add(e);const t=(0,d.f)(c.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(G).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,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=>!Y()&&!K.has(e))(e)&&(K.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(H,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/etherealengine-docs/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/etherealengine-docs/docs","mainDocId":"overview","docs":[{"id":"creator/avatars/readme","path":"/etherealengine-docs/docs/creator/avatars/","sidebar":"tutorialSidebar"},{"id":"creator/concepts/editor_scenes_locations","path":"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations","sidebar":"tutorialSidebar"},{"id":"creator/concepts/readme","path":"/etherealengine-docs/docs/creator/concepts/","sidebar":"tutorialSidebar"},{"id":"creator/development/actions_event_sourcing","path":"/etherealengine-docs/docs/creator/development/actions_event_sourcing","sidebar":"tutorialSidebar"},{"id":"creator/development/behave_graph","path":"/etherealengine-docs/docs/creator/development/behave_graph","sidebar":"tutorialSidebar"},{"id":"creator/development/ecs","path":"/etherealengine-docs/docs/creator/development/ecs","sidebar":"tutorialSidebar"},{"id":"creator/development/networking","path":"/etherealengine-docs/docs/creator/development/networking","sidebar":"tutorialSidebar"},{"id":"creator/development/projects_overview","path":"/etherealengine-docs/docs/creator/development/projects_overview","sidebar":"tutorialSidebar"},{"id":"creator/development/readme","path":"/etherealengine-docs/docs/creator/development/","sidebar":"tutorialSidebar"},{"id":"creator/development/state_management","path":"/etherealengine-docs/docs/creator/development/state_management","sidebar":"tutorialSidebar"},{"id":"creator/importing_assets/readme","path":"/etherealengine-docs/docs/creator/importing_assets/","sidebar":"tutorialSidebar"},{"id":"creator/readme","path":"/etherealengine-docs/docs/creator/","sidebar":"tutorialSidebar"},{"id":"creator/studio/readme","path":"/etherealengine-docs/docs/creator/studio/","sidebar":"tutorialSidebar"},{"id":"creator/testing/debugging","path":"/etherealengine-docs/docs/creator/testing/debugging","sidebar":"tutorialSidebar"},{"id":"creator/testing/debugging_deployed_instanceservers","path":"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers","sidebar":"tutorialSidebar"},{"id":"creator/testing/debugging_device_wsl","path":"/etherealengine-docs/docs/creator/testing/debugging_device_wsl","sidebar":"tutorialSidebar"},{"id":"creator/testing/readme","path":"/etherealengine-docs/docs/creator/testing/","sidebar":"tutorialSidebar"},{"id":"creator/testing/reasonable_code","path":"/etherealengine-docs/docs/creator/testing/reasonable_code","sidebar":"tutorialSidebar"},{"id":"creator/testing/test_driven_development","path":"/etherealengine-docs/docs/creator/testing/test_driven_development","sidebar":"tutorialSidebar"},{"id":"creator/testing/testing_intro","path":"/etherealengine-docs/docs/creator/testing/testing_intro","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/ethereal_engine/readme","path":"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/ethereal_engine/unity_bridge","path":"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/ethereal_engine/unreal_bridge","path":"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/readme","path":"/etherealengine-docs/docs/creator/tutorials/","sidebar":"tutorialSidebar"},{"id":"guest/readme","path":"/etherealengine-docs/docs/guest/","sidebar":"tutorialSidebar"},{"id":"host/Admin_Dashboard/readme","path":"/etherealengine-docs/docs/host/Admin_Dashboard/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/AWS_setup","path":"/etherealengine-docs/docs/host/devops_deployment/AWS_setup","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/database_migrations","path":"/etherealengine-docs/docs/host/devops_deployment/database_migrations","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/docker_desktop","path":"/etherealengine-docs/docs/host/devops_deployment/docker_desktop","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/installing_projects","path":"/etherealengine-docs/docs/host/devops_deployment/installing_projects","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/managing_remote_kubernetes","path":"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/microk8s_linux","path":"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/microk8s_windows","path":"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/minikube","path":"/etherealengine-docs/docs/host/devops_deployment/minikube","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/readme","path":"/etherealengine-docs/docs/host/devops_deployment/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/release_helm_chart","path":"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/setup_github_oauth_for_projects","path":"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/tutorials/ethereal_control_center/getting_started","path":"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/tutorials/ethereal_control_center/readme","path":"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/tutorials/readme","path":"/etherealengine-docs/docs/host/devops_deployment/tutorials/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/upgrade_helm_deployment","path":"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment","sidebar":"tutorialSidebar"},{"id":"host/installation/advanced_setup","path":"/etherealengine-docs/docs/host/installation/advanced_setup","sidebar":"tutorialSidebar"},{"id":"host/installation/basic_setup","path":"/etherealengine-docs/docs/host/installation/basic_setup","sidebar":"tutorialSidebar"},{"id":"host/installation/docker","path":"/etherealengine-docs/docs/host/installation/docker","sidebar":"tutorialSidebar"},{"id":"host/installation/install_troubleshooting","path":"/etherealengine-docs/docs/host/installation/install_troubleshooting","sidebar":"tutorialSidebar"},{"id":"host/installation/mac_os_x","path":"/etherealengine-docs/docs/host/installation/mac_os_x","sidebar":"tutorialSidebar"},{"id":"host/installation/opensearch","path":"/etherealengine-docs/docs/host/installation/opensearch","sidebar":"tutorialSidebar"},{"id":"host/installation/readme","path":"/etherealengine-docs/docs/host/installation/","sidebar":"tutorialSidebar"},{"id":"host/installation/running_on_static_IP","path":"/etherealengine-docs/docs/host/installation/running_on_static_IP","sidebar":"tutorialSidebar"},{"id":"host/installation/windows","path":"/etherealengine-docs/docs/host/installation/windows","sidebar":"tutorialSidebar"},{"id":"host/installation/windows_wsl","path":"/etherealengine-docs/docs/host/installation/windows_wsl","sidebar":"tutorialSidebar"},{"id":"host/readme","path":"/etherealengine-docs/docs/host/","sidebar":"tutorialSidebar"},{"id":"overview","path":"/etherealengine-docs/docs/","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/etherealengine-docs/docs/","label":"Overview"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en","es"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"},"es":{"label":"Espa\xf1ol","direction":"ltr","htmlLang":"es","calendar":"gregory","path":"es"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.4.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.4.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.4.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.0"},"docusaurus-theme-search-algolia":{"type":"package","name":"@docusaurus/theme-search-algolia","version":"2.4.0"}}}'),c={siteConfig:a.default,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},u=r.createContext(c);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:c},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(412),o=n(5742),i=n(8780),l=n(7452);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},r.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),r.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),r.createElement(c,{error:t}))}function c(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function u(e){let{error:t,tryAgain:n}=e;return r.createElement(p,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(o.Z,null,r.createElement("title",null,"Page Error")),r.createElement(l.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const d=e=>r.createElement(u,e);class p 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??d)(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),c=n(412);const u=a.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:h,"data-noBrokenLinkCheck":g,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.Z)(),{withBaseUrl:k}=(0,d.C)(),_=(0,a.useContext)(u),E=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>E.current));const S=p||f;const x=(0,s.Z)(S),C=S?.replace("pathname://","");let T=void 0!==C?(A=C,b&&(e=>e.startsWith("/"))(A)?k(A):A):void 0;var A;T&&x&&(T=(0,i.applyTrailingSlash)(T,{trailingSlash:y,baseUrl:w}));const L=(0,a.useRef)(!1),R=n?o.OL:o.rU,P=c.Z.canUseIntersectionObserver,N=(0,a.useRef)(),O=()=>{L.current||null==T||(window.docusaurus.preload(T),L.current=!0)};(0,a.useEffect)((()=>(!P&&x&&null!=T&&window.docusaurus.prefetch(T),()=>{P&&N.current&&N.current.disconnect()})),[N,T,P,x]);const I=T?.startsWith("#")??!1,D=!T||!x||I;return D||g||_.collectLink(T),D?a.createElement("a",(0,r.Z)({ref:E,href:T},S&&!x&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(R,(0,r.Z)({},v,{onMouseEnter:O,onTouchStart:O,innerRef:e=>{E.current=e,P&&e&&x&&(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:h,activeClassName:m}))}const f=a.forwardRef(p)},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 <Translate> children",t),new Error("The Docusaurus <Translate> 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:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();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:()=>b,gA:()=>f,WS:()=>m,_r:()=>d,Jo:()=>v,zh:()=>p,yW:()=>g,gB:()=>h});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=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}function c(e,t){const n=s(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={},d=()=>i("docusaurus-plugin-content-docs")??u,p=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 f(e){void 0===e&&(e={});const t=d(),{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 m(e){void 0===e&&(e={});const t=f(e),{pathname:n}=(0,r.TH)();if(!t)return;return{activePlugin:t,activeVersion:s(t.pluginData,n)}}function h(e){return p(e).versions}function g(e){const t=p(e);return l(t)}function b(e){const t=p(e),{pathname:n}=(0,r.TH)();return c(t,n)}function v(e){const t=p(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:c(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"}))}},7452:(e,t,n)=>{"use strict";n.d(t,{Z:()=>Rt});var r=n(7294),a=n(6010),o=n(4763),i=n(833),l=n(7462),s=n(6550),c=n(5999),u=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,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.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 h(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 g=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(h,{className:v.skipToContent})}var w=n(6668),k=n(9689);function _(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 E={closeButton:"closeButton_CVFx"};function S(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,c.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",E.closeButton,e.className)}),r.createElement(_,{width:14,height:14,strokeWidth:3.1}))}const x={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)(x.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(S,{onClick:n,className:T.announcementBarClose}))}var L=n(3163),R=n(2466);var P=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,P.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 P.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(2949),j=n(2389);function z(e){return r.createElement("svg",(0,l.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 U(e){return r.createElement("svg",(0,l.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 $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function q(e){let{className:t,buttonClassName:n,value:o,onChange:i}=e;const l=(0,j.Z)(),s=(0,c.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"===o?(0,c.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)($.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",$.toggleButton,!l&&$.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===o?"light":"dark"),disabled:!l,title:s,"aria-label":s,"aria-live":"polite"},r.createElement(z,{className:(0,a.Z)($.toggleIcon,$.lightToggleIcon)}),r.createElement(U,{className:(0,a.Z)($.toggleIcon,$.darkToggleIcon)})))}const H=r.memo(q),G={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function Z(e){let{className:t}=e;const n=(0,w.L)().navbar.style,a=(0,w.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:i}=(0,B.I)();return a?null:r.createElement(H,{className:t,buttonClassName:"dark"===n?G.darkNavbarColorModeToggle:void 0,value:o,onChange:i})}var V=n(1327);function W(){return r.createElement(V.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,L.e)();return r.createElement("button",{type:"button","aria-label":(0,c.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(_,{color:"var(--ifm-color-emphasis-600)"}))}function Y(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(W,null),r.createElement(Z,{className:"margin-right--md"}),r.createElement(K,null))}var Q=n(9960),X=n(4996),J=n(3919),ee=n(8022),te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const p=(0,X.Z)(a),f=(0,X.Z)(t),m=(0,X.Z)(o,{forcePrependBaseUrl:!0}),h=i&&o&&!(0,J.Z)(o),g=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,h&&r.createElement(te.Z,c&&{width:12,height:12}))};return o?r.createElement(Q.Z,(0,l.Z)({href:u?m:o},d,g)):r.createElement(Q.Z,(0,l.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?(0,ee.F)(n,t.pathname):t.pathname.startsWith(f)},d,g))}function re(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(ne,(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 ae(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ne,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function oe(e){let{mobile:t=!1,position:n,...a}=e;const o=t?ae:re;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(6043),le=n(8596),se=n(2263);function ce(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!(0,ee.F)(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:o,onClick:i,...s}=e;const c=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[c]),r.createElement("div",{ref:c,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(ne,(0,l.Z)({"aria-haspopup":"true","aria-expanded":u,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(!u))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>r.createElement(qe,(0,l.Z)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:o,onClick:i,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,se.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=ce(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(ne,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),f()}}),c.children??c.label),r.createElement(ie.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(qe,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function pe(e){let{mobile:t=!1,...n}=e;const a=t?de:ue;return r.createElement(a,n)}var fe=n(4711);function me(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 he="iconLanguage_nlXk";function ge(){return r.createElement("svg",{width:"15",height:"15",className:"DocSearch-Control-Key-Icon"},r.createElement("path",{d:"M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953",strokeWidth:"1.2",stroke:"currentColor",fill:"none",strokeLinecap:"square"}))}var be=n(830),ve=["translations"];function ye(){return ye=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},ye.apply(this,arguments)}function we(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,a,o=[],i=!0,l=!1;try{for(n=n.call(e);!(i=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);i=!0);}catch(s){l=!0,a=s}finally{try{i||null==n.return||n.return()}finally{if(l)throw a}}return o}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return ke(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ke(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ke(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function _e(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var Ee="Ctrl";var Se=r.forwardRef((function(e,t){var n=e.translations,a=void 0===n?{}:n,o=_e(e,ve),i=a.buttonText,l=void 0===i?"Search":i,s=a.buttonAriaLabel,c=void 0===s?"Search":s,u=we((0,r.useState)(null),2),d=u[0],p=u[1];return(0,r.useEffect)((function(){"undefined"!=typeof navigator&&(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?p("\u2318"):p(Ee))}),[]),r.createElement("button",ye({type:"button",className:"DocSearch DocSearch-Button","aria-label":c},o,{ref:t}),r.createElement("span",{className:"DocSearch-Button-Container"},r.createElement(be.W,null),r.createElement("span",{className:"DocSearch-Button-Placeholder"},l)),r.createElement("span",{className:"DocSearch-Button-Keys"},null!==d&&r.createElement(r.Fragment,null,r.createElement("kbd",{className:"DocSearch-Button-Key"},d===Ee?r.createElement(ge,null):d),r.createElement("kbd",{className:"DocSearch-Button-Key"},"K"))))})),xe=n(5742),Ce=n(6177),Te=n(239),Ae=n(3320);var Le=n(3935);const Re={button:{buttonText:(0,c.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"}),buttonAriaLabel:(0,c.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"})},modal:{searchBox:{resetButtonTitle:(0,c.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),resetButtonAriaLabel:(0,c.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),cancelButtonText:(0,c.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"}),cancelButtonAriaLabel:(0,c.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"})},startScreen:{recentSearchesTitle:(0,c.I)({id:"theme.SearchModal.startScreen.recentSearchesTitle",message:"Recent",description:"The title for recent searches"}),noRecentSearchesText:(0,c.I)({id:"theme.SearchModal.startScreen.noRecentSearchesText",message:"No recent searches",description:"The text when no recent searches"}),saveRecentSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.saveRecentSearchButtonTitle",message:"Save this search",description:"The label for save recent search button"}),removeRecentSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.removeRecentSearchButtonTitle",message:"Remove this search from history",description:"The label for remove recent search button"}),favoriteSearchesTitle:(0,c.I)({id:"theme.SearchModal.startScreen.favoriteSearchesTitle",message:"Favorite",description:"The title for favorite searches"}),removeFavoriteSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle",message:"Remove this search from favorites",description:"The label for remove favorite search button"})},errorScreen:{titleText:(0,c.I)({id:"theme.SearchModal.errorScreen.titleText",message:"Unable to fetch results",description:"The title for error screen of search modal"}),helpText:(0,c.I)({id:"theme.SearchModal.errorScreen.helpText",message:"You might want to check your network connection.",description:"The help text for error screen of search modal"})},footer:{selectText:(0,c.I)({id:"theme.SearchModal.footer.selectText",message:"to select",description:"The explanatory text of the action for the enter key"}),selectKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.selectKeyAriaLabel",message:"Enter key",description:"The ARIA label for the Enter key button that makes the selection"}),navigateText:(0,c.I)({id:"theme.SearchModal.footer.navigateText",message:"to navigate",description:"The explanatory text of the action for the Arrow up and Arrow down key"}),navigateUpKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.navigateUpKeyAriaLabel",message:"Arrow up",description:"The ARIA label for the Arrow up key button that makes the navigation"}),navigateDownKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.navigateDownKeyAriaLabel",message:"Arrow down",description:"The ARIA label for the Arrow down key button that makes the navigation"}),closeText:(0,c.I)({id:"theme.SearchModal.footer.closeText",message:"to close",description:"The explanatory text of the action for Escape key"}),closeKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.closeKeyAriaLabel",message:"Escape key",description:"The ARIA label for the Escape key button that close the modal"}),searchByText:(0,c.I)({id:"theme.SearchModal.footer.searchByText",message:"Search by",description:"The text explain that the search is making by Algolia"})},noResultsScreen:{noResultsText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.noResultsText",message:"No results for",description:"The text explains that there are no results for the following search"}),suggestedQueryText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.suggestedQueryText",message:"Try searching for",description:"The text for the suggested query when no results are found for the following search"}),reportMissingResultsText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsText",message:"Believe this query should return results?",description:"The text for the question where the user thinks there are missing results"}),reportMissingResultsLinkText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText",message:"Let us know.",description:"The text for the link to report missing results"})}},placeholder:(0,c.I)({id:"theme.SearchModal.placeholder",message:"Search docs",description:"The placeholder of the input of the DocSearch pop-up modal"})};let Pe=null;function Ne(e){let{hit:t,children:n}=e;return r.createElement(Q.Z,{to:t.url},n)}function Oe(e){let{state:t,onClose:n}=e;const a=(0,Ce.M)();return r.createElement(Q.Z,{to:a(t.query),onClick:n},r.createElement(c.Z,{id:"theme.SearchBar.seeAll",values:{count:t.context.nbHits}},"See all {count} results"))}function Ie(e){let{contextualSearch:t,externalUrlRegex:a,...o}=e;const{siteMetadata:i}=(0,se.Z)(),c=(0,Te.l)(),u=function(){const{locale:e,tags:t}=(0,Ae._q)();return[`language:${e}`,t.map((e=>`docusaurus_tag:${e}`))]}(),d=o.searchParameters?.facetFilters??[],p=t?function(e,t){const n=e=>"string"==typeof e?[e]:e;return[...n(e),...n(t)]}(u,d):d,f={...o.searchParameters,facetFilters:p},m=(0,s.k6)(),h=(0,r.useRef)(null),g=(0,r.useRef)(null),[b,v]=(0,r.useState)(!1),[y,w]=(0,r.useState)(void 0),k=(0,r.useCallback)((()=>Pe?Promise.resolve():Promise.all([n.e(1426).then(n.bind(n,1426)),Promise.all([n.e(3312),n.e(6945)]).then(n.bind(n,6945)),Promise.all([n.e(3312),n.e(8894)]).then(n.bind(n,8894))]).then((e=>{let[{DocSearchModal:t}]=e;Pe=t}))),[]),_=(0,r.useCallback)((()=>{k().then((()=>{h.current=document.createElement("div"),document.body.insertBefore(h.current,document.body.firstChild),v(!0)}))}),[k,v]),E=(0,r.useCallback)((()=>{v(!1),h.current?.remove()}),[v]),S=(0,r.useCallback)((e=>{k().then((()=>{v(!0),w(e.key)}))}),[k,v,w]),x=(0,r.useRef)({navigate(e){let{itemUrl:t}=e;(0,ee.F)(a,t)?window.location.href=t:m.push(t)}}).current,C=(0,r.useRef)((e=>o.transformItems?o.transformItems(e):e.map((e=>({...e,url:c(e.url)}))))).current,T=(0,r.useMemo)((()=>e=>r.createElement(Oe,(0,l.Z)({},e,{onClose:E}))),[E]),A=(0,r.useCallback)((e=>(e.addAlgoliaAgent("docusaurus",i.docusaurusVersion),e)),[i.docusaurusVersion]);return function(e){var t=e.isOpen,n=e.onOpen,a=e.onClose,o=e.onInput,i=e.searchButtonRef;r.useEffect((function(){function e(e){var r;(27===e.keyCode&&t||"k"===(null===(r=e.key)||void 0===r?void 0:r.toLowerCase())&&(e.metaKey||e.ctrlKey)||!function(e){var t=e.target,n=t.tagName;return t.isContentEditable||"INPUT"===n||"SELECT"===n||"TEXTAREA"===n}(e)&&"/"===e.key&&!t)&&(e.preventDefault(),t?a():document.body.classList.contains("DocSearch--active")||document.body.classList.contains("DocSearch--active")||n()),i&&i.current===document.activeElement&&o&&/[a-zA-Z0-9]/.test(String.fromCharCode(e.keyCode))&&o(e)}return window.addEventListener("keydown",e),function(){window.removeEventListener("keydown",e)}}),[t,n,a,o,i])}({isOpen:b,onOpen:_,onClose:E,onInput:S,searchButtonRef:g}),r.createElement(r.Fragment,null,r.createElement(xe.Z,null,r.createElement("link",{rel:"preconnect",href:`https://${o.appId}-dsn.algolia.net`,crossOrigin:"anonymous"})),r.createElement(Se,{onTouchStart:k,onFocus:k,onMouseOver:k,onClick:_,ref:g,translations:Re.button}),b&&Pe&&h.current&&(0,Le.createPortal)(r.createElement(Pe,(0,l.Z)({onClose:E,initialScrollY:window.scrollY,initialQuery:y,navigator:x,transformItems:C,hitComponent:Ne,transformSearchClient:A},o.searchPagePath&&{resultsFooterComponent:T},o,{searchParameters:f,placeholder:Re.placeholder,translations:Re.modal})),h.current))}function De(){const{siteConfig:e}=(0,se.Z)();return r.createElement(Ie,e.themeConfig.algolia)}const Me={searchBox:"searchBox_ZlJk"};function Fe(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,Me.searchBox)},t)}var Be=n(143),je=n(2802);var ze=n(373);const Ue=e=>e.docs.find((t=>t.id===e.mainDocId));const $e={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:d}}=(0,se.Z)(),p=(0,fe.l)(),{search:f,hash:m}=(0,s.TH)(),h=[...n,...u.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],g=t?(0,c.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(pe,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(me,{className:he}),g),items:h}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(Fe,{className:n},r.createElement(De,null))},dropdown:pe,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,Be.Iw)(a),s=(0,je.vY)(t,a);return null===s?null:r.createElement(oe,(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,Be.Iw)(a),s=(0,je.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(oe,(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,je.lO)(a)[0],s=t??i.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(oe,(0,l.Z)({},o,{label:s,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...u}=e;const{search:d,hash:p}=(0,s.TH)(),f=(0,Be.Iw)(n),m=(0,Be.gB)(n),{savePreferredVersionName:h}=(0,ze.J)(n),g=[...o,...m.map((e=>{const t=f.alternateDocVersions[e.name]??Ue(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>h(e.name)}})),...i],b=(0,je.lO)(n)[0],v=t&&g.length>1?(0,c.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&g.length>1?void 0:Ue(b).path;return g.length<=1?r.createElement(oe,(0,l.Z)({},u,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(pe,(0,l.Z)({},u,{mobile:t,label:v,to:y,items:g,isActive:a?()=>!1:void 0}))}};function qe(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=$e[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function He(){const e=(0,L.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(qe,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ge(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.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 Ze(){const e=0===(0,w.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Ge,{onClick:()=>t.hide()}),t.content)}function Ve(){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(Y,null),primaryMenu:r.createElement(He,null),secondaryMenu:r.createElement(Ze,null)}):null}const We={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ke(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Ye(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,R.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i<o.current)return void n(!0);if(a.current)return void(a.current=!1);const l=r?.scrollY,s=document.documentElement.scrollHeight-o.current,c=window.innerHeight;l&&i>=l?n(!1):i+c<s&&n(!0)})),(0,u.S)((t=>{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,"aria-label":(0,c.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[We.navbarHideable,!s&&We.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Ke,{onClick:i.toggle}),r.createElement(Ve,null))}var Qe=n(8780);const Xe={errorBoundaryError:"errorBoundaryError_a6uf"};function Je(e){return r.createElement("button",(0,l.Z)({type:"button"},e),r.createElement(c.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function et(e){let{error:t}=e;const n=(0,Qe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{className:Xe.errorBoundaryError},n)}class tt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const nt="right";function rt(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 at(){const{toggle:e,shown:t}=(0,L.e)();return r.createElement("button",{onClick:e,"aria-label":(0,c.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(rt,null))}const ot={colorModeToggle:"colorModeToggle_DEke"};function it(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(tt,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},r.createElement(qe,e)))))}function lt(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 st(){const e=(0,L.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??nt)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement(lt,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(at,null),r.createElement(W,null),r.createElement(it,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(it,{items:a}),r.createElement(Z,{className:ot.colorModeToggle}),!o&&r.createElement(Fe,null,r.createElement(De,null)))})}function ct(){return r.createElement(Ye,null,r.createElement(st,null))}function ut(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,c=(0,X.Z)(n),u=(0,X.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(Q.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?u:a}:{to:c},s),o,a&&!(0,J.Z)(a)&&r.createElement(te.Z,null))}function dt(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(ut,{item:t}))}function pt(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(dt,{key:t,item:e})))))}function ft(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(pt,{key:t,column:e}))))}function mt(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function ht(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(ut,{item:t})}function gt(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(ht,{item:e}),t.length!==n+1&&r.createElement(mt,null))))))}function bt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(ft,{columns:t}):r.createElement(gt,{links:t})}var vt=n(941);const yt={footerLogoLink:"footerLogoLink_BH7S"};function wt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,X.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(vt.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function kt(e){let{logo:t}=e;return t.href?r.createElement(Q.Z,{href:t.href,className:yt.footerLogoLink,target:t.target},r.createElement(wt,{logo:t})):r.createElement(wt,{logo:t})}function _t(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Et(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 St(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(Et,{style:o,links:n&&n.length>0&&r.createElement(bt,{links:n}),logo:a&&r.createElement(kt,{logo:a}),copyright:t&&r.createElement(_t,{copyright:t})})}const xt=r.memo(St),Ct=(0,P.Qc)([B.S,k.pl,R.OC,ze.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 Tt(e){let{children:t}=e;return r.createElement(Ct,null,t)}function At(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("div",{className:"margin-vert--lg"},r.createElement(Je,{onClick:n,className:"button button--primary shadow--lw"})),r.createElement("hr",null),r.createElement("div",{className:"margin-vert--md"},r.createElement(et,{error:t})))))}const Lt={mainWrapper:"mainWrapper_z2l0"};function Rt(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:c}=e;return(0,b.t)(),r.createElement(Tt,null,r.createElement(i.d,{title:s,description:c}),r.createElement(y,null),r.createElement(A,null),r.createElement(ct,null),r.createElement("div",{id:d,className:(0,a.Z)(g.k.wrapper.main,Lt.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(At,e)},t)),!n&&r.createElement(xt,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),c=n(941);function u(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(c.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:c}}=(0,s.L)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,i.Z)(c?.href||"/"),h=n?"":t,g=c?.alt??h;return a.createElement(o.Z,(0,r.Z)({to:m},f,c?.target&&{target:c.target}),c&&a.createElement(u,{logo:c,alt:g,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},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:()=>c});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 c(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:c,className:u,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:c[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],u)},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"},c={display:"block",overflow:"visible",height:"auto"};function u(e,t){const n=t?s:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return 0;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}function p(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=function(){const t=e.scrollHeight;return{transition:`height ${r?.duration??d(t)}ms ${r?.easing??i}`,height:`${t}px`}}();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return u(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(a(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{a()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function f(e){if(!o.Z.canUseDOM)return e?s:c}function m(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const c=(0,a.useRef)(null);return p({collapsibleRef:c,collapsed:n,animation:o}),a.createElement(t,{ref:c,style:s?void 0:f(n),onTransitionEnd:e=>{"height"===e.propertyName&&(u(c.current,n),i?.(n))},className:l},r)}function h(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(m,(0,r.Z)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?h:m;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.WA)("docusaurus.announcement.dismiss"),c=(0,o.WA)("docusaurus.announcement.id"),u=()=>"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&&u()));(0,r.useEffect)((()=>{o(u())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&d(!1),!r&&u()||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:()=>g,S:()=>h});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),c="theme",u=(0,i.WA)(c),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=>{u.set(p(e))};function h(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&&u.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),u.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!==c)return;const t=u.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 g(){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:()=>g,Oh:()=>y});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(2802),s=n(902),c=n(12);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.WA)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.WA)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.WA)(u(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 h(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function g(e){let{children:t}=e;return l.cE?r.createElement(h,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])}}function y(){const e=(0,a._r)(),[t]=b();function n(n){const r=e[n],{preferredVersionName:a}=t[n];return r.versions.find((e=>e.name===a))??null}const r=Object.keys(e);return Object.fromEntries(r.map((e=>[e,n(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}},3163:(e,t,n)=>{"use strict";n.d(t,{M:()=>d,e:()=>p});var r=n(7294),a=n(3102),o=n(7524),i=n(1980),l=n(6668),s=n(902);const c=r.createContext(void 0);function u(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.i)(),n=!e&&"mobile"===t,[s,c]=(0,r.useState)(!1);(0,i.Rb)((()=>{if(s)return c(!1),!1}));const u=(0,r.useCallback)((()=>{c((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&c(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:s})),[e,n,u,s])}function d(e){let{children:t}=e;const n=u();return r.createElement(c.Provider,{value:n},t)}function p(){const e=r.useContext(c);if(void 0===e)throw new s.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}},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)}}),[])}},6177:(e,t,n)=>{"use strict";n.d(t,{K:()=>l,M:()=>s});var r=n(7294),a=n(2263),o=n(1980);const i="q";function l(){return(0,o.Nc)(i)}function s(){const{siteConfig:{baseUrl:e,themeConfig:t}}=(0,a.Z)(),{algolia:{searchPagePath:n}}=t;return(0,r.useCallback)((t=>`${e}${n}?${i}=${encodeURIComponent(t)}`),[e,n])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>c});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 c(){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:{}}},2802:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>p,_F:()=>h,cE:()=>d,hI:()=>k,lO:()=>v,vY:()=>w,oz:()=>y,s1:()=>b});var r=n(7294),a=n(6550),o=n(8790),i=n(143),l=n(373),s=n(1116);function c(e){return Array.from(new Set(e))}var u=n(8596);const d=!!i._r;function p(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=p(t);if(e)return e}}}const f=(e,t)=>void 0!==e&&(0,u.Mg)(e,t),m=(e,t)=>e.some((e=>h(e,t)));function h(e,t){return"link"===e.type?f(e.href,t):"category"===e.type&&(f(e.href,t)||m(e.items,t))}function g(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,u.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,u.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function b(){const e=(0,s.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?g({sidebarItems:e.items,pathname:t}):null}function v(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>c([t,n,a].filter(Boolean))),[t,n,a])}function y(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function w(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${c(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function k(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,c=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:c}}},2128:(e,t,n)=>{"use strict";n.d(t,{p:()=>a});var r=n(2263);function a(e){const{siteConfig:t}=(0,r.Z)(),{title:n,titleDelimiter:a}=t;return e?.trim().length?`${e.trim()} ${a} ${n}`:n}},1980:(e,t,n)=>{"use strict";n.d(t,{Nc:()=>c,Rb:()=>l});var r=n(7294),a=n(6550),o=n(1688),i=n(902);function l(e){!function(e){const t=(0,a.k6)(),n=(0,i.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function s(e){return function(e){const t=(0,a.k6)();return(0,o.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}function c(e){const t=s(e)??"",n=function(){const e=(0,a.k6)();return(0,r.useCallback)(((t,n,r)=>{const a=new URLSearchParams(e.location.search);n?a.set(t,n):a.delete(t),(r?.push?e.push:e.replace)({search:a.toString()})}),[e])}();return[t,(0,r.useCallback)(((t,r)=>{n(e,t,r)}),[n,e])]}},833:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>u,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),c=n(2128);function u(e){let{title:t,description:n,keywords:a,image:i,children:l}=e;const u=(0,c.p)(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,u),t&&r.createElement("meta",{property:"og:title",content:u}),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:()=>c,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+\.)?(?<name>\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 c(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8022:(e,t,n)=>{"use strict";function r(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}n.d(t,{F:()=>r})},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:()=>p,OC:()=>s,RF:()=>d});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 c(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const u=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),a=(0,r.useRef)(u()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();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=(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&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>i,_q:()=>s,os:()=>l});var r=n(143),a=n(2263),o=n(373);const i="default";function l(e,t){return`docs-${e}-${t}`}function s(){const{i18n:e}=(0,a.Z)(),t=(0,r._r)(),n=(0,r.WS)(),s=(0,o.Oh)();const c=[i,...Object.keys(t).map((function(e){const r=n?.activePlugin.pluginId===e?n.activeVersion:void 0,a=s[e],o=t[e].versions.find((e=>e.isLast));return l(e,(r??a??o).name)}))];return{locale:e.currentLocale,tags:c}}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>s});n(7294),n(1688);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(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),i=!0),null}var t}let i=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function s(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,listen:t}}(e);const n=o(t?.persistence);return null===n?l:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"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}},6278:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){const{siteConfig:{themeConfig:e}}=(0,r.Z)();return e}},239:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(7294),a=n(8022),o=n(4996),i=n(6278);function l(){const{withBaseUrl:e}=(0,o.C)(),{algolia:{externalUrlRegex:t,replaceSearchResultPathname:n}}=(0,i.L)();return(0,r.useCallback)((r=>{const o=new URL(r);if((0,a.F)(t,o.href))return r;const i=`${o.pathname+o.hash}`;return e(function(e,t){return t?e.replaceAll(new RegExp(t.from,"g"),t.to):e}(i,n))}),[e,t,n])}},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)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},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.getErrorCausalChain=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}});var o=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},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;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{Z:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},9318:(e,t,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<a;n+=1,r+=1)e[n]=e[r];e.pop()}const i=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],i=t&&t.split("/")||[],l=e&&a(e),s=t&&a(t),c=l||s;if(e&&a(e)?i=r:r.length&&(i.pop(),i=i.concat(r)),!i.length)return"/";if(i.length){var u=i[i.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=i.length;p>=0;p--){var f=i[p];"."===f?o(i,p):".."===f?(o(i,p),d++):d&&(o(i,p),d--)}if(!c)for(;d--;d)i.unshift("..");!c||""===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 c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function 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;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),h||(0,l.Z)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,o=!(-1===window.navigator.userAgent.indexOf("Trident")),i=e,c=i.forceRefresh,w=void 0!==c&&c,k=i.getUserConfirmation,_=void 0===k?g:k,E=i.keyLength,S=void 0===E?6:E,x=e.basename?d(s(e.basename)):"";function C(e){var t=e||{},n=t.key,r=t.state,a=window.location,o=a.pathname+a.search+a.hash;return x&&(o=u(o,x)),f(o,r,n)}function T(){return Math.random().toString(36).substr(2,S)}var A=m();function L(e){(0,r.Z)(U,e),U.length=n.length,A.notifyListeners(U.location,U.action)}function R(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||O(C(e.state))}function P(){O(C(y()))}var N=!1;function O(e){if(N)N=!1,L();else{A.confirmTransitionTo(e,"POP",_,(function(t){t?L({action:"POP",location:e}):function(e){var t=U.location,n=D.indexOf(t.key);-1===n&&(n=0);var r=D.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(N=!0,F(a))}(e)}))}}var I=C(y()),D=[I.key];function M(e){return x+p(e)}function F(e){n.go(e)}var B=0;function j(e){1===(B+=e)&&1===e?(window.addEventListener(b,R),o&&window.addEventListener(v,P)):0===B&&(window.removeEventListener(b,R),o&&window.removeEventListener(v,P))}var z=!1;var U={length:n.length,action:"POP",location:I,createHref:M,push:function(e,t){var r="PUSH",o=f(e,t,T(),U.location);A.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.pushState({key:i,state:l},null,t),w)window.location.href=t;else{var s=D.indexOf(U.location.key),c=D.slice(0,s+1);c.push(o.key),D=c,L({action:r,location:o})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",o=f(e,t,T(),U.location);A.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.replaceState({key:i,state:l},null,t),w)window.location.replace(t);else{var s=D.indexOf(U.location.key);-1!==s&&(D[s]=o.key),L({action:r,location:o})}else window.location.replace(t)}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=A.setPrompt(e);return z||(j(1),z=!0),function(){return z&&(z=!1,j(-1)),t()}},listen:function(e){var t=A.appendListener(e);return j(1),function(){j(-1),t()}}};return U}var k="hashchange",_={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:s},slash:{encodePath:s,decodePath:s}};function E(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function S(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function x(e){window.location.replace(E(window.location.href)+"#"+e)}function C(e){void 0===e&&(e={}),h||(0,l.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,o=void 0===a?g:a,i=n.hashType,c=void 0===i?"slash":i,b=e.basename?d(s(e.basename)):"",v=_[c],y=v.encodePath,w=v.decodePath;function C(){var e=w(S());return b&&(e=u(e,b)),f(e)}var T=m();function A(e){(0,r.Z)(z,e),z.length=t.length,T.notifyListeners(z.location,z.action)}var L=!1,R=null;function P(){var e,t,n=S(),r=y(n);if(n!==r)x(r);else{var a=C(),i=z.location;if(!L&&(t=a,(e=i).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(R===p(a))return;R=null,function(e){if(L)L=!1,A();else{var t="POP";T.confirmTransitionTo(e,t,o,(function(n){n?A({action:t,location:e}):function(e){var t=z.location,n=D.lastIndexOf(p(t));-1===n&&(n=0);var r=D.lastIndexOf(p(e));-1===r&&(r=0);var a=n-r;a&&(L=!0,M(a))}(e)}))}}(a)}}var N=S(),O=y(N);N!==O&&x(O);var I=C(),D=[p(I)];function M(e){t.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?window.addEventListener(k,P):0===F&&window.removeEventListener(k,P)}var j=!1;var z={length:t.length,action:"POP",location:I,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=E(window.location.href)),n+"#"+y(b+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,z.location);T.confirmTransitionTo(r,n,o,(function(e){if(e){var t=p(r),a=y(b+t);if(S()!==a){R=t,function(e){window.location.hash=e}(a);var o=D.lastIndexOf(p(z.location)),i=D.slice(0,o+1);i.push(t),D=i,A({action:n,location:r})}else A()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,z.location);T.confirmTransitionTo(r,n,o,(function(e){if(e){var t=p(r),a=y(b+t);S()!==a&&(R=t,x(a));var o=D.indexOf(p(z.location));-1!==o&&(D[o]=t),A({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=T.setPrompt(e);return j||(B(1),j=!0),function(){return j&&(j=!1,B(-1)),t()}},listen:function(e){var t=T.appendListener(e);return B(1),function(){B(-1),t()}}};return z}function T(e,t,n){return Math.min(Math.max(e,t),n)}function A(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,o=void 0===a?["/"]:a,i=t.initialIndex,l=void 0===i?0:i,s=t.keyLength,c=void 0===s?6:s,u=m();function d(e){(0,r.Z)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function h(){return Math.random().toString(36).substr(2,c)}var g=T(l,0,o.length-1),b=o.map((function(e){return f(e,void 0,"string"==typeof e?h():e.key||h())})),v=p;function y(e){var t=T(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var w={length:b.length,action:"POP",location:b[g],index:g,entries:b,createHref:v,push:function(e,t){var r="PUSH",a=f(e,t,h(),w.location);u.confirmTransitionTo(a,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,h(),w.location);u.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<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},8679:(e,t,n)=>{"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 c=Object.defineProperty,u=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=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),h=s(n),g=0;g<i.length;++g){var b=i[g];if(!(o[b]||r&&r[b]||h&&h[b]||l&&l[b])){var v=p(n,b);try{c(t,b,v)}catch(y){}}}}return t}},1143:e=>{"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 c=[n,r,a,o,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},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:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?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),c=o.querySelector(r.barSelector),u=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,i(e,u,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*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");u(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),c=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),c!=document.body&&u(c,"nprogress-custom-parent"),c.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 c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);c(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<arguments.length;s++){for(var c in o=Object(arguments[s]))n.call(o,c)&&(l[c]=o[c]);if(t){i=t(o);for(var u=0;u<i.length;u++)r.call(o,i[u])&&(l[i[u]]=o[i[u]])}}return l}},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(l+=e.slice(i,f),i=f+d.length,p)l+=p[1];else{var m=e[i],h=n[2],g=n[3],b=n[4],v=n[5],y=n[6],w=n[7];l&&(r.push(l),l="");var k=null!=h&&null!=m&&m!==h,_="+"===y||"*"===y,E="?"===y||"*"===y,S=n[2]||u,x=b||v;r.push({name:g||o++,prefix:h||"",delimiter:S,optional:E,repeat:_,partial:k,asterisk:!!w,pattern:x?c(x):w?".*":"[^"+s(S)+"]+?"})}}return i<e.length&&(l+=e.substr(i)),l&&r.push(l),r}function i(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function l(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var o="",l=t||{},s=(a||{}).pretty?i:encodeURIComponent,c=0;c<e.length;c++){var u=e[c];if("string"!=typeof u){var d,p=l[u.name];if(null==p){if(u.optional){u.partial&&(o+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=s(p[f]),!n[c].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");o+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):s(p),!n[c].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');o+=u.prefix+d}}else o+=u}return o}}function s(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,o=!1!==n.end,i="",l=0;l<e.length;l++){var c=e[l];if("string"==typeof c)i+=s(c);else{var p=s(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+p+f+")*"),i+=f=c.optional?c.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var m=s(n.delimiter||"/"),h=i.slice(-m.length)===m;return a||(i=(h?i.slice(0,-m.length):i)+"(?:"+m+"(?=$))?"),i+=o?"$":a&&h?"":"(?="+m+"|$)",u(new RegExp("^"+i,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(f(e[a],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(o(e,n),t,n)}(e,t,n)}},7410:(e,t,n)=>{"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(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,o;switch(n=n||{},r.util.type(t)){case"Object":if(o=r.util.objId(t),n[o])return n[o];for(var i in a={},n[o]=a,t)t.hasOwnProperty(i)&&(a[i]=e(t[i],n));return a;case"Array":return o=r.util.objId(t),n[o]?n[o]:(a=[],n[o]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var o=(a=a||r.languages)[e],i={};for(var l in o)if(o.hasOwnProperty(l)){if(l==t)for(var s in n)n.hasOwnProperty(s)&&(i[s]=n[s]);n.hasOwnProperty(l)||(i[l]=o[l])}var c=a[e];return a[e]=i,r.languages.DFS(r.languages,(function(t,n){n===c&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,a,o){o=o||{};var i=r.util.objId;for(var l in t)if(t.hasOwnProperty(l)){n.call(t,l,t[l],a||l);var s=t[l],c=r.util.type(s);"Object"!==c||o[i(s)]?"Array"!==c||o[i(s)]||(o[i(s)]=!0,e(s,n,l,o)):(o[i(s)]=!0,e(s,n,null,o))}}},plugins:{},highlight:function(e,t,n){var o={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",o),o.tokens=r.tokenize(o.code,o.grammar),r.hooks.run("after-tokenize",o),a.stringify(r.util.encode(o.tokens),o.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new l;return s(a,a.head,e),i(e,a,t,a.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,o=0;a=n[o++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function o(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var o=a[1].length;a.index+=o,a[0]=a[0].slice(o)}return a}function i(e,t,n,l,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(d&&d.cause==p+","+m)return;var h=f[m],g=h.inside,b=!!h.lookbehind,v=!!h.greedy,y=h.alias;if(v&&!h.pattern.global){var w=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,w+"g")}for(var k=h.pattern||h,_=l.next,E=u;_!==t.tail&&!(d&&E>=d.reach);E+=_.value.length,_=_.next){var S=_.value;if(t.length>e.length)return;if(!(S instanceof a)){var x,C=1;if(v){if(!(x=o(k,E,e,b))||x.index>=e.length)break;var T=x.index,A=x.index+x[0].length,L=E;for(L+=_.value.length;T>=L;)L+=(_=_.next).value.length;if(E=L-=_.value.length,_.value instanceof a)continue;for(var R=_;R!==t.tail&&(L<A||"string"==typeof R.value);R=R.next)C++,L+=R.value.length;C--,S=e.slice(E,L),x.index-=E}else if(!(x=o(k,0,S,b)))continue;T=x.index;var P=x[0],N=S.slice(0,T),O=S.slice(T+P.length),I=E+S.length;d&&I>d.reach&&(d.reach=I);var D=_.prev;if(N&&(D=s(t,D,N),E+=N.length),c(t,D,C),_=s(t,D,new a(p,g?r.tokenize(P,g):P,y,P)),O&&s(t,_,O),C>1){var M={cause:p+","+m,reach:I};i(e,t,n,_.prev,E,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 c(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var o={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(o.classes,i):o.classes.push(i)),r.hooks.run("wrap",o);var l="";for(var s in o.attributes)l+=" "+s+'="'+(o.attributes[s]||"").replace(/"/g,""")+'"';return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+l+">"+o.content+"</"+o.tag+">"},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},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:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.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<a.length;i++)o[a[i]]=e.languages.bash[a[i]];e.languages.shell=e.languages.bash}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},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(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(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]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/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<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+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(/<inner>/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__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a=t[n];if("code"===a.type){var o=a.content[1],i=a.content[3];if(o&&i&&"code-language"===o.type&&"code-block"===i.type&&"string"==typeof o.content){var l=o.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),s="language-"+(l=(/[a-z][\w-]*/i.exec(l)||[""])[0].toLowerCase());i.alias?"string"==typeof i.alias?i.alias=[i.alias,s]:i.alias.push(s):i.alias=[s]}}else e(a.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var o=t.classes[r],c=/language-(.+)/.exec(o);if(c){n=c[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(i,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),s(n);var r=l[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var p="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=p,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(p);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var i=RegExp(e.languages.markup.tag.pattern.source,"gi"),l={amp:"&",lt:"<",gt:">",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;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var o=p(/^\($/,/^\)$/);if(-1===o)continue;for(;n<o;n++){var i=u(0);"variable"===i.type&&(f(i,"variable-input"),a.push(i.content))}n=o+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),a.length>0)){var l=p(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s<l;s++){var c=t[s];"variable"===c.type&&a.indexOf(c.content)>=0&&f(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return!1}return!0}function p(e,r){for(var a=1,o=n;o<t.length;o++){var i=t[o],l=i.content;if("punctuation"===i.type&&"string"==typeof l)if(e.test(l))a++;else if(r.test(l)&&0===--a)return o}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,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 c(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 u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,u={},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 u[n]=a,n})).join(""),n,r),p=Object.keys(u);return i=0,function e(t){for(var n=0;n<t.length;n++){if(i>=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=c(u[a]),f=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),f){var h=[f];e(h),m.push.apply(m,h)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(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<a;r++){var o=n[r];if("string"!=typeof o){var i=o.content;if(Array.isArray(i))if("template-string"===o.type){var l=i[1];if(3===i.length&&"string"!=typeof l&&"embedded-code"===l.type){var s=p(l),c=l.alias,d=Array.isArray(c)?c[0]:c,f=e.languages[d];if(!f)continue;i[1]=u(s,f,d)}}else t(i);else"string"!=typeof i&&t([i])}}}(t.tokens)}))}(a),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],o=e.languages.javascript[a];"RegExp"===e.util.type(o)&&(o=e.languages.javascript[a]={pattern:o});var i=o.inside||{};o.inside=i,i["maybe-class-name"]=/^[A-Z][\s\S]*/}}(a),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function o(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/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.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=<BRACES>/.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;r<t.length;r++){var a=t[r],o=!1;if("string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?n.length>0&&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);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(s+=i(t[r+1]),t.splice(r+1,1)),r>0&&("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<l.length&&!(a>=o.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=o[a],d=n.tokenStack[u],p="string"==typeof c?c:c.content,f=t(r,u),m=p.indexOf(f);if(m>-1){++a;var h=p.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(m+f.length),v=[];h&&v.push.apply(v,i([h])),v.push(g),b&&v.push.apply(v,i([b])),"string"==typeof c?l.splice.apply(l,[s,1].concat(v)):c.content=v}}else c.content&&i(c.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 <a href="https://webplatform.github.io/docs/">WebPlatform.org documentation</a>. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (<code>.comment</code> can become <code>.namespace--comment</code>) or replace them with your defined ones (like <code>.editor__comment</code>). 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 <code>highlightAll</code> and <code>highlightAllUnder</code> 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<r;n++)t[e[n]]=!0;return t}function r(e){var n={},r=[];function a(r,o){if(!(r in n)){o.push(r);var i=o.indexOf(r);if(i<o.length-1)throw new Error("Circular dependency: "+o.slice(i).join(" -> "));var l={},s=e[r];if(s){function c(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,c),t(s.optional,c),t(s.modify,c)}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),c=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(c),l=(l||[]).map(c);var u=n(i),d=n(l);i.forEach((function e(n){var r=s[n];t(r&&r.require,(function(t){t in d||(u[t]=!0,e(t))}))}));for(var p,f=r(s),m=u;a(m);){for(var h in p={},m){var g=s[h];t(g&&g.modify,(function(e){e in d&&(p[e]=!0)}))}for(var b in d)if(!(b in u))for(var v in f(b))if(v in u){p[b]=!0;break}for(var y in m=p)u[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 c(e){if(e in l)return l[e];s[e]=!0;var a,u=[];for(var d in t(e))d in n&&u.push(d);if(0===u.length)a=r(e);else{var p=i(u.map((function(e){var t=c(e);return delete s[e],t})));o?a=o(p,(function(){return r(e)})):r(e)}return l[e]=a}for(var u in n)c(u);var d=[];for(var p in s)d.push(l[p]);return i(d)}(f,u,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(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(i(227));var l=new Set,s={};function c(e,t){u(e,t),u(e+"Capture",t)}function u(e,t){for(s[e]=t,e=0;e<t.length;e++)l.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),p=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f=Object.prototype.hasOwnProperty,m={},h={};function g(e,t,n,r,a,o,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){b[e]=new g(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];b[t]=new g(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){b[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){b[e]=new g(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){b[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){b[e]=new g(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){b[e]=new g(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){b[e]=new g(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){b[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)}));var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}function w(e,t,n,r){var a=b.hasOwnProperty(t)?b[t]:null;(null!==a?0===a.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!f.call(h,e)||!f.call(m,e)&&(p.test(e)?h[e]=!0:(m[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)})),b.xlinkHref=new g("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)}));var k=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,_=60103,E=60106,S=60107,x=60108,C=60114,T=60109,A=60110,L=60112,R=60113,P=60120,N=60115,O=60116,I=60121,D=60128,M=60129,F=60130,B=60131;if("function"==typeof Symbol&&Symbol.for){var j=Symbol.for;_=j("react.element"),E=j("react.portal"),S=j("react.fragment"),x=j("react.strict_mode"),C=j("react.profiler"),T=j("react.provider"),A=j("react.context"),L=j("react.forward_ref"),R=j("react.suspense"),P=j("react.suspense_list"),N=j("react.memo"),O=j("react.lazy"),I=j("react.block"),j("react.scope"),D=j("react.opaque.id"),M=j("react.debug_trace_mode"),F=j("react.offscreen"),B=j("react.legacy_hidden")}var z,U="function"==typeof Symbol&&Symbol.iterator;function $(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=U&&e[U]||e["@@iterator"])?e:null}function q(e){if(void 0===z)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);z=t&&t[1]||""}return"\n"+z+e}var H=!1;function G(e,t){if(!e||H)return"";H=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(s){var r=s}Reflect.construct(e,[],t)}else{try{t.call()}catch(s){r=s}e.call(t.prototype)}else{try{throw Error()}catch(s){r=s}e()}}catch(s){if(s&&r&&"string"==typeof s.stack){for(var a=s.stack.split("\n"),o=r.stack.split("\n"),i=a.length-1,l=o.length-1;1<=i&&0<=l&&a[i]!==o[l];)l--;for(;1<=i&&0<=l;i--,l--)if(a[i]!==o[l]){if(1!==i||1!==l)do{if(i--,0>--l||a[i]!==o[l])return"\n"+a[i].replace(" at new "," at ")}while(1<=i&&0<=l);break}}}finally{H=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?q(e):""}function Z(e){switch(e.tag){case 5:return q(e.type);case 16:return q("Lazy");case 13:return q("Suspense");case 19:return q("SuspenseList");case 0:case 2:case 15:return e=G(e.type,!1);case 11:return e=G(e.type.render,!1);case 22:return e=G(e.type._render,!1);case 1:return e=G(e.type,!0);default:return""}}function V(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case S:return"Fragment";case E:return"Portal";case C:return"Profiler";case x:return"StrictMode";case R:return"Suspense";case P:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case A:return(e.displayName||"Context")+".Consumer";case T:return(e._context.displayName||"Context")+".Provider";case L:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case N:return V(e.type);case I:return V(e._render);case O:t=e._payload,e=e._init;try{return V(e(t))}catch(n){}}return null}function W(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function K(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function Y(e){e._valueTracker||(e._valueTracker=function(e){var t=K(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function Q(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=K(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function X(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function J(e,t){var n=t.checked;return a({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=W(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function te(e,t){null!=(t=t.checked)&&w(e,"checked",t,!1)}function ne(e,t){te(e,t);var n=W(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ae(e,t.type,n):t.hasOwnProperty("defaultValue")&&ae(e,t.type,W(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function re(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ae(e,t,n){"number"===t&&X(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function oe(e,t){return e=a({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function ie(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+W(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function le(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(i(91));return a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function se(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(i(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(i(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:W(n)}}function ce(e,t){var n=W(t.value),r=W(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ue(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var de={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function pe(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function fe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?pe(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var me,he,ge=(he=function(e,t){if(e.namespaceURI!==de.svg||"innerHTML"in e)e.innerHTML=t;else{for((me=me||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return he(e,t)}))}:he);function be(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var ve={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ye=["Webkit","ms","Moz","O"];function we(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||ve.hasOwnProperty(e)&&ve[e]?(""+t).trim():t+"px"}function ke(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=we(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(ve).forEach((function(e){ye.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ve[t]=ve[e]}))}));var _e=a({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Ee(e,t){if(t){if(_e[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(i(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(i(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(i(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(i(62))}}function Se(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function xe(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var Ce=null,Te=null,Ae=null;function Le(e){if(e=na(e)){if("function"!=typeof Ce)throw Error(i(280));var t=e.stateNode;t&&(t=aa(t),Ce(e.stateNode,e.type,t))}}function Re(e){Te?Ae?Ae.push(e):Ae=[e]:Te=e}function Pe(){if(Te){var e=Te,t=Ae;if(Ae=Te=null,Le(e),t)for(e=0;e<t.length;e++)Le(t[e])}}function Ne(e,t){return e(t)}function Oe(e,t,n,r,a){return e(t,n,r,a)}function Ie(){}var De=Ne,Me=!1,Fe=!1;function Be(){null===Te&&null===Ae||(Ie(),Pe())}function je(e,t){var n=e.stateNode;if(null===n)return null;var r=aa(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(i(231,t,typeof n));return n}var ze=!1;if(d)try{var Ue={};Object.defineProperty(Ue,"passive",{get:function(){ze=!0}}),window.addEventListener("test",Ue,Ue),window.removeEventListener("test",Ue,Ue)}catch(he){ze=!1}function $e(e,t,n,r,a,o,i,l,s){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(u){this.onError(u)}}var qe=!1,He=null,Ge=!1,Ze=null,Ve={onError:function(e){qe=!0,He=e}};function We(e,t,n,r,a,o,i,l,s){qe=!1,He=null,$e.apply(Ve,arguments)}function Ke(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(1026&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Ye(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Qe(e){if(Ke(e)!==e)throw Error(i(188))}function Xe(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ke(e)))throw Error(i(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var o=a.alternate;if(null===o){if(null!==(r=a.return)){n=r;continue}break}if(a.child===o.child){for(o=a.child;o;){if(o===n)return Qe(a),e;if(o===r)return Qe(a),t;o=o.sibling}throw Error(i(188))}if(n.return!==r.return)n=a,r=o;else{for(var l=!1,s=a.child;s;){if(s===n){l=!0,n=a,r=o;break}if(s===r){l=!0,r=a,n=o;break}s=s.sibling}if(!l){for(s=o.child;s;){if(s===n){l=!0,n=o,r=a;break}if(s===r){l=!0,r=o,n=a;break}s=s.sibling}if(!l)throw Error(i(189))}}if(n.alternate!==r)throw Error(i(190))}if(3!==n.tag)throw Error(i(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function Je(e,t){for(var n=e.alternate;null!==t;){if(t===e||t===n)return!0;t=t.return}return!1}var et,tt,nt,rt,at=!1,ot=[],it=null,lt=null,st=null,ct=new Map,ut=new Map,dt=[],pt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function ft(e,t,n,r,a){return{blockedOn:e,domEventName:t,eventSystemFlags:16|n,nativeEvent:a,targetContainers:[r]}}function mt(e,t){switch(e){case"focusin":case"focusout":it=null;break;case"dragenter":case"dragleave":lt=null;break;case"mouseover":case"mouseout":st=null;break;case"pointerover":case"pointerout":ct.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":ut.delete(t.pointerId)}}function ht(e,t,n,r,a,o){return null===e||e.nativeEvent!==o?(e=ft(t,n,r,a,o),null!==t&&(null!==(t=na(t))&&tt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==a&&-1===t.indexOf(a)&&t.push(a),e)}function gt(e){var t=ta(e.target);if(null!==t){var n=Ke(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Ye(n)))return e.blockedOn=t,void rt(e.lanePriority,(function(){o.unstable_runWithPriority(e.priority,(function(){nt(n)}))}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function bt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Xt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=na(n))&&tt(t),e.blockedOn=n,!1;t.shift()}return!0}function vt(e,t,n){bt(e)&&n.delete(t)}function yt(){for(at=!1;0<ot.length;){var e=ot[0];if(null!==e.blockedOn){null!==(e=na(e.blockedOn))&&et(e);break}for(var t=e.targetContainers;0<t.length;){var n=Xt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n){e.blockedOn=n;break}t.shift()}null===e.blockedOn&&ot.shift()}null!==it&&bt(it)&&(it=null),null!==lt&&bt(lt)&&(lt=null),null!==st&&bt(st)&&(st=null),ct.forEach(vt),ut.forEach(vt)}function wt(e,t){e.blockedOn===t&&(e.blockedOn=null,at||(at=!0,o.unstable_scheduleCallback(o.unstable_NormalPriority,yt)))}function kt(e){function t(t){return wt(t,e)}if(0<ot.length){wt(ot[0],e);for(var n=1;n<ot.length;n++){var r=ot[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==it&&wt(it,e),null!==lt&&wt(lt,e),null!==st&&wt(st,e),ct.forEach(t),ut.forEach(t),n=0;n<dt.length;n++)(r=dt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<dt.length&&null===(n=dt[0]).blockedOn;)gt(n),null===n.blockedOn&&dt.shift()}function _t(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var Et={animationend:_t("Animation","AnimationEnd"),animationiteration:_t("Animation","AnimationIteration"),animationstart:_t("Animation","AnimationStart"),transitionend:_t("Transition","TransitionEnd")},St={},xt={};function Ct(e){if(St[e])return St[e];if(!Et[e])return e;var t,n=Et[e];for(t in n)if(n.hasOwnProperty(t)&&t in xt)return St[e]=n[t];return e}d&&(xt=document.createElement("div").style,"AnimationEvent"in window||(delete Et.animationend.animation,delete Et.animationiteration.animation,delete Et.animationstart.animation),"TransitionEvent"in window||delete Et.transitionend.transition);var Tt=Ct("animationend"),At=Ct("animationiteration"),Lt=Ct("animationstart"),Rt=Ct("transitionend"),Pt=new Map,Nt=new Map,Ot=["abort","abort",Tt,"animationEnd",At,"animationIteration",Lt,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Rt,"transitionEnd","waiting","waiting"];function It(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],a=e[n+1];a="on"+(a[0].toUpperCase()+a.slice(1)),Nt.set(r,t),Pt.set(r,a),c(a,[r])}}(0,o.unstable_now)();var Dt=8;function Mt(e){if(0!=(1&e))return Dt=15,1;if(0!=(2&e))return Dt=14,2;if(0!=(4&e))return Dt=13,4;var t=24&e;return 0!==t?(Dt=12,t):0!=(32&e)?(Dt=11,32):0!==(t=192&e)?(Dt=10,t):0!=(256&e)?(Dt=9,256):0!==(t=3584&e)?(Dt=8,t):0!=(4096&e)?(Dt=7,4096):0!==(t=4186112&e)?(Dt=6,t):0!==(t=62914560&e)?(Dt=5,t):67108864&e?(Dt=4,67108864):0!=(134217728&e)?(Dt=3,134217728):0!==(t=805306368&e)?(Dt=2,t):0!=(1073741824&e)?(Dt=1,1073741824):(Dt=8,e)}function Ft(e,t){var n=e.pendingLanes;if(0===n)return Dt=0;var r=0,a=0,o=e.expiredLanes,i=e.suspendedLanes,l=e.pingedLanes;if(0!==o)r=o,a=Dt=15;else if(0!==(o=134217727&n)){var s=o&~i;0!==s?(r=Mt(s),a=Dt):0!==(l&=o)&&(r=Mt(l),a=Dt)}else 0!==(o=n&~i)?(r=Mt(o),a=Dt):0!==l&&(r=Mt(l),a=Dt);if(0===r)return 0;if(r=n&((0>(r=31-qt(r))?0:1<<r)<<1)-1,0!==t&&t!==r&&0==(t&i)){if(Mt(t),a<=Dt)return t;Dt=a}if(0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)a=1<<(n=31-qt(t)),r|=e[n],t&=~a;return r}function Bt(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function jt(e,t){switch(e){case 15:return 1;case 14:return 2;case 12:return 0===(e=zt(24&~t))?jt(10,t):e;case 10:return 0===(e=zt(192&~t))?jt(8,t):e;case 8:return 0===(e=zt(3584&~t))&&(0===(e=zt(4186112&~t))&&(e=512)),e;case 2:return 0===(t=zt(805306368&~t))&&(t=268435456),t}throw Error(i(358,e))}function zt(e){return e&-e}function Ut(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function $t(e,t,n){e.pendingLanes|=t;var r=t-1;e.suspendedLanes&=r,e.pingedLanes&=r,(e=e.eventTimes)[t=31-qt(t)]=n}var qt=Math.clz32?Math.clz32:function(e){return 0===e?32:31-(Ht(e)/Gt|0)|0},Ht=Math.log,Gt=Math.LN2;var Zt=o.unstable_UserBlockingPriority,Vt=o.unstable_runWithPriority,Wt=!0;function Kt(e,t,n,r){Me||Ie();var a=Qt,o=Me;Me=!0;try{Oe(a,e,t,n,r)}finally{(Me=o)||Be()}}function Yt(e,t,n,r){Vt(Zt,Qt.bind(null,e,t,n,r))}function Qt(e,t,n,r){var a;if(Wt)if((a=0==(4&t))&&0<ot.length&&-1<pt.indexOf(e))e=ft(null,e,t,n,r),ot.push(e);else{var o=Xt(e,t,n,r);if(null===o)a&&mt(e,r);else{if(a){if(-1<pt.indexOf(e))return e=ft(o,e,t,n,r),void ot.push(e);if(function(e,t,n,r,a){switch(t){case"focusin":return it=ht(it,e,t,n,r,a),!0;case"dragenter":return lt=ht(lt,e,t,n,r,a),!0;case"mouseover":return st=ht(st,e,t,n,r,a),!0;case"pointerover":var o=a.pointerId;return ct.set(o,ht(ct.get(o)||null,e,t,n,r,a)),!0;case"gotpointercapture":return o=a.pointerId,ut.set(o,ht(ut.get(o)||null,e,t,n,r,a)),!0}return!1}(o,e,t,n,r))return;mt(e,r)}Ir(e,t,r,null,n)}}}function Xt(e,t,n,r){var a=xe(r);if(null!==(a=ta(a))){var o=Ke(a);if(null===o)a=null;else{var i=o.tag;if(13===i){if(null!==(a=Ye(o)))return a;a=null}else if(3===i){if(o.stateNode.hydrate)return 3===o.tag?o.stateNode.containerInfo:null;a=null}else o!==a&&(a=null)}}return Ir(e,t,r,a,n),null}var Jt=null,en=null,tn=null;function nn(){if(tn)return tn;var e,t,n=en,r=n.length,a="value"in Jt?Jt.value:Jt.textContent,o=a.length;for(e=0;e<r&&n[e]===a[e];e++);var i=r-e;for(t=1;t<=i&&n[r-t]===a[o-t];t++);return tn=a.slice(e,1<t?1-t:void 0)}function rn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function an(){return!0}function on(){return!1}function ln(e){function t(t,n,r,a,o){for(var i in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=a,this.target=o,this.currentTarget=null,e)e.hasOwnProperty(i)&&(t=e[i],this[i]=t?t(a):a[i]);return this.isDefaultPrevented=(null!=a.defaultPrevented?a.defaultPrevented:!1===a.returnValue)?an:on,this.isPropagationStopped=on,this}return a(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=an)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=an)},persist:function(){},isPersistent:an}),t}var sn,cn,un,dn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},pn=ln(dn),fn=a({},dn,{view:0,detail:0}),mn=ln(fn),hn=a({},fn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Tn,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==un&&(un&&"mousemove"===e.type?(sn=e.screenX-un.screenX,cn=e.screenY-un.screenY):cn=sn=0,un=e),sn)},movementY:function(e){return"movementY"in e?e.movementY:cn}}),gn=ln(hn),bn=ln(a({},hn,{dataTransfer:0})),vn=ln(a({},fn,{relatedTarget:0})),yn=ln(a({},dn,{animationName:0,elapsedTime:0,pseudoElement:0})),wn=a({},dn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),kn=ln(wn),_n=ln(a({},dn,{data:0})),En={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},Sn={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},xn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Cn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=xn[e])&&!!t[e]}function Tn(){return Cn}var An=a({},fn,{key:function(e){if(e.key){var t=En[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=rn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?Sn[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Tn,charCode:function(e){return"keypress"===e.type?rn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?rn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),Ln=ln(An),Rn=ln(a({},hn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Pn=ln(a({},fn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Tn})),Nn=ln(a({},dn,{propertyName:0,elapsedTime:0,pseudoElement:0})),On=a({},hn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),In=ln(On),Dn=[9,13,27,32],Mn=d&&"CompositionEvent"in window,Fn=null;d&&"documentMode"in document&&(Fn=document.documentMode);var Bn=d&&"TextEvent"in window&&!Fn,jn=d&&(!Mn||Fn&&8<Fn&&11>=Fn),zn=String.fromCharCode(32),Un=!1;function $n(e,t){switch(e){case"keyup":return-1!==Dn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function qn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Hn=!1;var Gn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Zn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Gn[e.type]:"textarea"===t}function Vn(e,t,n,r){Re(r),0<(t=Mr(t,"onChange")).length&&(n=new pn("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Wn=null,Kn=null;function Yn(e){Ar(e,0)}function Qn(e){if(Q(ra(e)))return e}function Xn(e,t){if("change"===e)return t}var Jn=!1;if(d){var er;if(d){var tr="oninput"in document;if(!tr){var nr=document.createElement("div");nr.setAttribute("oninput","return;"),tr="function"==typeof nr.oninput}er=tr}else er=!1;Jn=er&&(!document.documentMode||9<document.documentMode)}function rr(){Wn&&(Wn.detachEvent("onpropertychange",ar),Kn=Wn=null)}function ar(e){if("value"===e.propertyName&&Qn(Kn)){var t=[];if(Vn(t,Kn,e,xe(e)),e=Yn,Me)e(t);else{Me=!0;try{Ne(e,t)}finally{Me=!1,Be()}}}}function or(e,t,n){"focusin"===e?(rr(),Kn=n,(Wn=t).attachEvent("onpropertychange",ar)):"focusout"===e&&rr()}function ir(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Qn(Kn)}function lr(e,t){if("click"===e)return Qn(t)}function sr(e,t){if("input"===e||"change"===e)return Qn(t)}var cr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},ur=Object.prototype.hasOwnProperty;function dr(e,t){if(cr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!ur.call(t,n[r])||!cr(e[n[r]],t[n[r]]))return!1;return!0}function pr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function fr(e,t){var n,r=pr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=pr(r)}}function mr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function hr(){for(var e=window,t=X();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=X((e=t.contentWindow).document)}return t}function gr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var br=d&&"documentMode"in document&&11>=document.documentMode,vr=null,yr=null,wr=null,kr=!1;function _r(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;kr||null==vr||vr!==X(r)||("selectionStart"in(r=vr)&&gr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},wr&&dr(wr,r)||(wr=r,0<(r=Mr(yr,"onSelect")).length&&(t=new pn("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=vr)))}It("cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focusin focus focusout blur input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),It("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),It(Ot,2);for(var Er="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),Sr=0;Sr<Er.length;Sr++)Nt.set(Er[Sr],0);u("onMouseEnter",["mouseout","mouseover"]),u("onMouseLeave",["mouseout","mouseover"]),u("onPointerEnter",["pointerout","pointerover"]),u("onPointerLeave",["pointerout","pointerover"]),c("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),c("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),c("onBeforeInput",["compositionend","keypress","textInput","paste"]),c("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var xr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Cr=new Set("cancel close invalid load scroll toggle".split(" ").concat(xr));function Tr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,a,o,l,s,c){if(We.apply(this,arguments),qe){if(!qe)throw Error(i(198));var u=He;qe=!1,He=null,Ge||(Ge=!0,Ze=u)}}(r,t,void 0,e),e.currentTarget=null}function Ar(e,t){t=0!=(4&t);for(var n=0;n<e.length;n++){var r=e[n],a=r.event;r=r.listeners;e:{var o=void 0;if(t)for(var i=r.length-1;0<=i;i--){var l=r[i],s=l.instance,c=l.currentTarget;if(l=l.listener,s!==o&&a.isPropagationStopped())break e;Tr(a,l,c),o=s}else for(i=0;i<r.length;i++){if(s=(l=r[i]).instance,c=l.currentTarget,l=l.listener,s!==o&&a.isPropagationStopped())break e;Tr(a,l,c),o=s}}}if(Ge)throw e=Ze,Ge=!1,Ze=null,e}function Lr(e,t){var n=oa(t),r=e+"__bubble";n.has(r)||(Or(t,e,2,!1),n.add(r))}var Rr="_reactListening"+Math.random().toString(36).slice(2);function Pr(e){e[Rr]||(e[Rr]=!0,l.forEach((function(t){Cr.has(t)||Nr(t,!1,e,null),Nr(t,!0,e,null)})))}function Nr(e,t,n,r){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,o=n;if("selectionchange"===e&&9!==n.nodeType&&(o=n.ownerDocument),null!==r&&!t&&Cr.has(e)){if("scroll"!==e)return;a|=2,o=r}var i=oa(o),l=e+"__"+(t?"capture":"bubble");i.has(l)||(t&&(a|=4),Or(o,e,a,t),i.add(l))}function Or(e,t,n,r){var a=Nt.get(t);switch(void 0===a?2:a){case 0:a=Kt;break;case 1:a=Yt;break;default:a=Qt}n=a.bind(null,t,n,e),a=void 0,!ze||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(a=!0),r?void 0!==a?e.addEventListener(t,n,{capture:!0,passive:a}):e.addEventListener(t,n,!0):void 0!==a?e.addEventListener(t,n,{passive:a}):e.addEventListener(t,n,!1)}function Ir(e,t,n,r,a){var o=r;if(0==(1&t)&&0==(2&t)&&null!==r)e:for(;;){if(null===r)return;var i=r.tag;if(3===i||4===i){var l=r.stateNode.containerInfo;if(l===a||8===l.nodeType&&l.parentNode===a)break;if(4===i)for(i=r.return;null!==i;){var s=i.tag;if((3===s||4===s)&&((s=i.stateNode.containerInfo)===a||8===s.nodeType&&s.parentNode===a))return;i=i.return}for(;null!==l;){if(null===(i=ta(l)))return;if(5===(s=i.tag)||6===s){r=o=i;continue e}l=l.parentNode}}r=r.return}!function(e,t,n){if(Fe)return e(t,n);Fe=!0;try{return De(e,t,n)}finally{Fe=!1,Be()}}((function(){var r=o,a=xe(n),i=[];e:{var l=Pt.get(e);if(void 0!==l){var s=pn,c=e;switch(e){case"keypress":if(0===rn(n))break e;case"keydown":case"keyup":s=Ln;break;case"focusin":c="focus",s=vn;break;case"focusout":c="blur",s=vn;break;case"beforeblur":case"afterblur":s=vn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":s=gn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":s=bn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":s=Pn;break;case Tt:case At:case Lt:s=yn;break;case Rt:s=Nn;break;case"scroll":s=mn;break;case"wheel":s=In;break;case"copy":case"cut":case"paste":s=kn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":s=Rn}var u=0!=(4&t),d=!u&&"scroll"===e,p=u?null!==l?l+"Capture":null:l;u=[];for(var f,m=r;null!==m;){var h=(f=m).stateNode;if(5===f.tag&&null!==h&&(f=h,null!==p&&(null!=(h=je(m,p))&&u.push(Dr(m,h,f)))),d)break;m=m.return}0<u.length&&(l=new s(l,c,null,n,a),i.push({event:l,listeners:u}))}}if(0==(7&t)){if(s="mouseout"===e||"pointerout"===e,(!(l="mouseover"===e||"pointerover"===e)||0!=(16&t)||!(c=n.relatedTarget||n.fromElement)||!ta(c)&&!c[Jr])&&(s||l)&&(l=a.window===a?a:(l=a.ownerDocument)?l.defaultView||l.parentWindow:window,s?(s=r,null!==(c=(c=n.relatedTarget||n.toElement)?ta(c):null)&&(c!==(d=Ke(c))||5!==c.tag&&6!==c.tag)&&(c=null)):(s=null,c=r),s!==c)){if(u=gn,h="onMouseLeave",p="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(u=Rn,h="onPointerLeave",p="onPointerEnter",m="pointer"),d=null==s?l:ra(s),f=null==c?l:ra(c),(l=new u(h,m+"leave",s,n,a)).target=d,l.relatedTarget=f,h=null,ta(a)===r&&((u=new u(p,m+"enter",c,n,a)).target=f,u.relatedTarget=d,h=u),d=h,s&&c)e:{for(p=c,m=0,f=u=s;f;f=Fr(f))m++;for(f=0,h=p;h;h=Fr(h))f++;for(;0<m-f;)u=Fr(u),m--;for(;0<f-m;)p=Fr(p),f--;for(;m--;){if(u===p||null!==p&&u===p.alternate)break e;u=Fr(u),p=Fr(p)}u=null}else u=null;null!==s&&Br(i,l,s,u,!1),null!==c&&null!==d&&Br(i,d,c,u,!0)}if("select"===(s=(l=r?ra(r):window).nodeName&&l.nodeName.toLowerCase())||"input"===s&&"file"===l.type)var g=Xn;else if(Zn(l))if(Jn)g=sr;else{g=ir;var b=or}else(s=l.nodeName)&&"input"===s.toLowerCase()&&("checkbox"===l.type||"radio"===l.type)&&(g=lr);switch(g&&(g=g(e,r))?Vn(i,g,n,a):(b&&b(e,l,r),"focusout"===e&&(b=l._wrapperState)&&b.controlled&&"number"===l.type&&ae(l,"number",l.value)),b=r?ra(r):window,e){case"focusin":(Zn(b)||"true"===b.contentEditable)&&(vr=b,yr=r,wr=null);break;case"focusout":wr=yr=vr=null;break;case"mousedown":kr=!0;break;case"contextmenu":case"mouseup":case"dragend":kr=!1,_r(i,n,a);break;case"selectionchange":if(br)break;case"keydown":case"keyup":_r(i,n,a)}var v;if(Mn)e:{switch(e){case"compositionstart":var y="onCompositionStart";break e;case"compositionend":y="onCompositionEnd";break e;case"compositionupdate":y="onCompositionUpdate";break e}y=void 0}else Hn?$n(e,n)&&(y="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(y="onCompositionStart");y&&(jn&&"ko"!==n.locale&&(Hn||"onCompositionStart"!==y?"onCompositionEnd"===y&&Hn&&(v=nn()):(en="value"in(Jt=a)?Jt.value:Jt.textContent,Hn=!0)),0<(b=Mr(r,y)).length&&(y=new _n(y,e,null,n,a),i.push({event:y,listeners:b}),v?y.data=v:null!==(v=qn(n))&&(y.data=v))),(v=Bn?function(e,t){switch(e){case"compositionend":return qn(t);case"keypress":return 32!==t.which?null:(Un=!0,zn);case"textInput":return(e=t.data)===zn&&Un?null:e;default:return null}}(e,n):function(e,t){if(Hn)return"compositionend"===e||!Mn&&$n(e,t)?(e=nn(),tn=en=Jt=null,Hn=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return jn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Mr(r,"onBeforeInput")).length&&(a=new _n("onBeforeInput","beforeinput",null,n,a),i.push({event:a,listeners:r}),a.data=v))}Ar(i,t)}))}function Dr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Mr(e,t){for(var n=t+"Capture",r=[];null!==e;){var a=e,o=a.stateNode;5===a.tag&&null!==o&&(a=o,null!=(o=je(e,n))&&r.unshift(Dr(e,o,a)),null!=(o=je(e,t))&&r.push(Dr(e,o,a))),e=e.return}return r}function Fr(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Br(e,t,n,r,a){for(var o=t._reactName,i=[];null!==n&&n!==r;){var l=n,s=l.alternate,c=l.stateNode;if(null!==s&&s===r)break;5===l.tag&&null!==c&&(l=c,a?null!=(s=je(n,o))&&i.unshift(Dr(n,s,l)):a||null!=(s=je(n,o))&&i.push(Dr(n,s,l))),n=n.return}0!==i.length&&e.push({event:t,listeners:i})}function jr(){}var zr=null,Ur=null;function $r(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function qr(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Hr="function"==typeof setTimeout?setTimeout:void 0,Gr="function"==typeof clearTimeout?clearTimeout:void 0;function Zr(e){1===e.nodeType?e.textContent="":9===e.nodeType&&(null!=(e=e.body)&&(e.textContent=""))}function Vr(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function Wr(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var Kr=0;var Yr=Math.random().toString(36).slice(2),Qr="__reactFiber$"+Yr,Xr="__reactProps$"+Yr,Jr="__reactContainer$"+Yr,ea="__reactEvents$"+Yr;function ta(e){var t=e[Qr];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Jr]||n[Qr]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=Wr(e);null!==e;){if(n=e[Qr])return n;e=Wr(e)}return t}n=(e=n).parentNode}return null}function na(e){return!(e=e[Qr]||e[Jr])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function ra(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(i(33))}function aa(e){return e[Xr]||null}function oa(e){var t=e[ea];return void 0===t&&(t=e[ea]=new Set),t}var ia=[],la=-1;function sa(e){return{current:e}}function ca(e){0>la||(e.current=ia[la],ia[la]=null,la--)}function ua(e,t){la++,ia[la]=e.current,e.current=t}var da={},pa=sa(da),fa=sa(!1),ma=da;function ha(e,t){var n=e.type.contextTypes;if(!n)return da;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,o={};for(a in n)o[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function ga(e){return null!=(e=e.childContextTypes)}function ba(){ca(fa),ca(pa)}function va(e,t,n){if(pa.current!==da)throw Error(i(168));ua(pa,t),ua(fa,n)}function ya(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var o in r=r.getChildContext())if(!(o in e))throw Error(i(108,V(t)||"Unknown",o));return a({},n,r)}function wa(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||da,ma=pa.current,ua(pa,e),ua(fa,fa.current),!0}function ka(e,t,n){var r=e.stateNode;if(!r)throw Error(i(169));n?(e=ya(e,t,ma),r.__reactInternalMemoizedMergedChildContext=e,ca(fa),ca(pa),ua(pa,e)):ca(fa),ua(fa,n)}var _a=null,Ea=null,Sa=o.unstable_runWithPriority,xa=o.unstable_scheduleCallback,Ca=o.unstable_cancelCallback,Ta=o.unstable_shouldYield,Aa=o.unstable_requestPaint,La=o.unstable_now,Ra=o.unstable_getCurrentPriorityLevel,Pa=o.unstable_ImmediatePriority,Na=o.unstable_UserBlockingPriority,Oa=o.unstable_NormalPriority,Ia=o.unstable_LowPriority,Da=o.unstable_IdlePriority,Ma={},Fa=void 0!==Aa?Aa:function(){},Ba=null,ja=null,za=!1,Ua=La(),$a=1e4>Ua?La:function(){return La()-Ua};function qa(){switch(Ra()){case Pa:return 99;case Na:return 98;case Oa:return 97;case Ia:return 96;case Da:return 95;default:throw Error(i(332))}}function Ha(e){switch(e){case 99:return Pa;case 98:return Na;case 97:return Oa;case 96:return Ia;case 95:return Da;default:throw Error(i(332))}}function Ga(e,t){return e=Ha(e),Sa(e,t)}function Za(e,t,n){return e=Ha(e),xa(e,t,n)}function Va(){if(null!==ja){var e=ja;ja=null,Ca(e)}Wa()}function Wa(){if(!za&&null!==Ba){za=!0;var e=0;try{var t=Ba;Ga(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Ba=null}catch(n){throw null!==Ba&&(Ba=Ba.slice(e+1)),xa(Pa,Va),n}finally{za=!1}}}var Ka=k.ReactCurrentBatchConfig;function Ya(e,t){if(e&&e.defaultProps){for(var n in t=a({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var Qa=sa(null),Xa=null,Ja=null,eo=null;function to(){eo=Ja=Xa=null}function no(e){var t=Qa.current;ca(Qa),e.type._context._currentValue=t}function ro(e,t){for(;null!==e;){var n=e.alternate;if((e.childLanes&t)===t){if(null===n||(n.childLanes&t)===t)break;n.childLanes|=t}else e.childLanes|=t,null!==n&&(n.childLanes|=t);e=e.return}}function ao(e,t){Xa=e,eo=Ja=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(0!=(e.lanes&t)&&(Mi=!0),e.firstContext=null)}function oo(e,t){if(eo!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(eo=e,t=1073741823),t={context:e,observedBits:t,next:null},null===Ja){if(null===Xa)throw Error(i(308));Ja=t,Xa.dependencies={lanes:0,firstContext:t,responders:null}}else Ja=Ja.next=t;return e._currentValue}var io=!1;function lo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function so(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function co(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function uo(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function po(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var a=null,o=null;if(null!==(n=n.firstBaseUpdate)){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===o?a=o=i:o=o.next=i,n=n.next}while(null!==n);null===o?a=o=t:o=o.next=t}else a=o=t;return n={baseState:r.baseState,firstBaseUpdate:a,lastBaseUpdate:o,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function fo(e,t,n,r){var o=e.updateQueue;io=!1;var i=o.firstBaseUpdate,l=o.lastBaseUpdate,s=o.shared.pending;if(null!==s){o.shared.pending=null;var c=s,u=c.next;c.next=null,null===l?i=u:l.next=u,l=c;var d=e.alternate;if(null!==d){var p=(d=d.updateQueue).lastBaseUpdate;p!==l&&(null===p?d.firstBaseUpdate=u:p.next=u,d.lastBaseUpdate=c)}}if(null!==i){for(p=o.baseState,l=0,d=u=c=null;;){s=i.lane;var f=i.eventTime;if((r&s)===s){null!==d&&(d=d.next={eventTime:f,lane:0,tag:i.tag,payload:i.payload,callback:i.callback,next:null});e:{var m=e,h=i;switch(s=t,f=n,h.tag){case 1:if("function"==typeof(m=h.payload)){p=m.call(f,p,s);break e}p=m;break e;case 3:m.flags=-4097&m.flags|64;case 0:if(null==(s="function"==typeof(m=h.payload)?m.call(f,p,s):m))break e;p=a({},p,s);break e;case 2:io=!0}}null!==i.callback&&(e.flags|=32,null===(s=o.effects)?o.effects=[i]:s.push(i))}else f={eventTime:f,lane:s,tag:i.tag,payload:i.payload,callback:i.callback,next:null},null===d?(u=d=f,c=p):d=d.next=f,l|=s;if(null===(i=i.next)){if(null===(s=o.shared.pending))break;i=s.next,s.next=null,o.lastBaseUpdate=s,o.shared.pending=null}}null===d&&(c=p),o.baseState=c,o.firstBaseUpdate=u,o.lastBaseUpdate=d,Ul|=l,e.lanes=l,e.memoizedState=p}}function mo(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=n,"function"!=typeof a)throw Error(i(191,a));a.call(r)}}}var ho=(new r.Component).refs;function go(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:a({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var bo={isMounted:function(e){return!!(e=e._reactInternals)&&Ke(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=ps(),a=fs(e),o=co(r,a);o.payload=t,null!=n&&(o.callback=n),uo(e,o),ms(e,a,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=ps(),a=fs(e),o=co(r,a);o.tag=1,o.payload=t,null!=n&&(o.callback=n),uo(e,o),ms(e,a,r)},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=ps(),r=fs(e),a=co(n,r);a.tag=2,null!=t&&(a.callback=t),uo(e,a),ms(e,r,n)}};function vo(e,t,n,r,a,o,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,o,i):!t.prototype||!t.prototype.isPureReactComponent||(!dr(n,r)||!dr(a,o))}function yo(e,t,n){var r=!1,a=da,o=t.contextType;return"object"==typeof o&&null!==o?o=oo(o):(a=ga(t)?ma:pa.current,o=(r=null!=(r=t.contextTypes))?ha(e,a):da),t=new t(n,o),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=bo,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=o),t}function wo(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&bo.enqueueReplaceState(t,t.state,null)}function ko(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=ho,lo(e);var o=t.contextType;"object"==typeof o&&null!==o?a.context=oo(o):(o=ga(t)?ma:pa.current,a.context=ha(e,o)),fo(e,n,a,r),a.state=e.memoizedState,"function"==typeof(o=t.getDerivedStateFromProps)&&(go(e,t,o,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&bo.enqueueReplaceState(a,a.state,null),fo(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.flags|=4)}var _o=Array.isArray;function Eo(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(i(309));var r=n.stateNode}if(!r)throw Error(i(147,e));var a=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===a?t.ref:(t=function(e){var t=r.refs;t===ho&&(t=r.refs={}),null===e?delete t[a]:t[a]=e},t._stringRef=a,t)}if("string"!=typeof e)throw Error(i(284));if(!n._owner)throw Error(i(290,e))}return e}function So(e,t){if("textarea"!==e.type)throw Error(i(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t))}function xo(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.flags=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Zs(e,t)).index=0,e.sibling=null,e}function o(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags=2,n):r:(t.flags=2,n):n}function l(t){return e&&null===t.alternate&&(t.flags=2),t}function s(e,t,n,r){return null===t||6!==t.tag?((t=Ys(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function c(e,t,n,r){return null!==t&&t.elementType===n.type?((r=a(t,n.props)).ref=Eo(e,t,n),r.return=e,r):((r=Vs(n.type,n.key,n.props,null,e.mode,r)).ref=Eo(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Qs(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,o){return null===t||7!==t.tag?((t=Ws(n,e.mode,r,o)).return=e,t):((t=a(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Ys(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case _:return(n=Vs(t.type,t.key,t.props,null,e.mode,n)).ref=Eo(e,null,t),n.return=e,n;case E:return(t=Qs(t,e.mode,n)).return=e,t}if(_o(t)||$(t))return(t=Ws(t,e.mode,n,null)).return=e,t;So(e,t)}return null}function f(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==a?null:s(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case _:return n.key===a?n.type===S?d(e,t,n.props.children,r,a):c(e,t,n,r):null;case E:return n.key===a?u(e,t,n,r):null}if(_o(n)||$(n))return null!==a?null:d(e,t,n,r,null);So(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r||"number"==typeof r)return s(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case _:return e=e.get(null===r.key?n:r.key)||null,r.type===S?d(t,e,r.props.children,a,r.key):c(t,e,r,a);case E:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a)}if(_o(r)||$(r))return d(t,e=e.get(n)||null,r,a,null);So(t,r)}return null}function h(a,i,l,s){for(var c=null,u=null,d=i,h=i=0,g=null;null!==d&&h<l.length;h++){d.index>h?(g=d,d=null):g=d.sibling;var b=f(a,d,l[h],s);if(null===b){null===d&&(d=g);break}e&&d&&null===b.alternate&&t(a,d),i=o(b,i,h),null===u?c=b:u.sibling=b,u=b,d=g}if(h===l.length)return n(a,d),c;if(null===d){for(;h<l.length;h++)null!==(d=p(a,l[h],s))&&(i=o(d,i,h),null===u?c=d:u.sibling=d,u=d);return c}for(d=r(a,d);h<l.length;h++)null!==(g=m(d,a,h,l[h],s))&&(e&&null!==g.alternate&&d.delete(null===g.key?h:g.key),i=o(g,i,h),null===u?c=g:u.sibling=g,u=g);return e&&d.forEach((function(e){return t(a,e)})),c}function g(a,l,s,c){var u=$(s);if("function"!=typeof u)throw Error(i(150));if(null==(s=u.call(s)))throw Error(i(151));for(var d=u=null,h=l,g=l=0,b=null,v=s.next();null!==h&&!v.done;g++,v=s.next()){h.index>g?(b=h,h=null):b=h.sibling;var y=f(a,h,v.value,c);if(null===y){null===h&&(h=b);break}e&&h&&null===y.alternate&&t(a,h),l=o(y,l,g),null===d?u=y:d.sibling=y,d=y,h=b}if(v.done)return n(a,h),u;if(null===h){for(;!v.done;g++,v=s.next())null!==(v=p(a,v.value,c))&&(l=o(v,l,g),null===d?u=v:d.sibling=v,d=v);return u}for(h=r(a,h);!v.done;g++,v=s.next())null!==(v=m(h,a,g,v.value,c))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),l=o(v,l,g),null===d?u=v:d.sibling=v,d=v);return e&&h.forEach((function(e){return t(a,e)})),u}return function(e,r,o,s){var c="object"==typeof o&&null!==o&&o.type===S&&null===o.key;c&&(o=o.props.children);var u="object"==typeof o&&null!==o;if(u)switch(o.$$typeof){case _:e:{for(u=o.key,c=r;null!==c;){if(c.key===u){if(7===c.tag){if(o.type===S){n(e,c.sibling),(r=a(c,o.props.children)).return=e,e=r;break e}}else if(c.elementType===o.type){n(e,c.sibling),(r=a(c,o.props)).ref=Eo(e,c,o),r.return=e,e=r;break e}n(e,c);break}t(e,c),c=c.sibling}o.type===S?((r=Ws(o.props.children,e.mode,s,o.key)).return=e,e=r):((s=Vs(o.type,o.key,o.props,null,e.mode,s)).ref=Eo(e,r,o),s.return=e,e=s)}return l(e);case E:e:{for(c=o.key;null!==r;){if(r.key===c){if(4===r.tag&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),(r=a(r,o.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=Qs(o,e.mode,s)).return=e,e=r}return l(e)}if("string"==typeof o||"number"==typeof o)return o=""+o,null!==r&&6===r.tag?(n(e,r.sibling),(r=a(r,o)).return=e,e=r):(n(e,r),(r=Ys(o,e.mode,s)).return=e,e=r),l(e);if(_o(o))return h(e,r,o,s);if($(o))return g(e,r,o,s);if(u&&So(e,o),void 0===o&&!c)switch(e.tag){case 1:case 22:case 0:case 11:case 15:throw Error(i(152,V(e.type)||"Component"))}return n(e,r)}}var Co=xo(!0),To=xo(!1),Ao={},Lo=sa(Ao),Ro=sa(Ao),Po=sa(Ao);function No(e){if(e===Ao)throw Error(i(174));return e}function Oo(e,t){switch(ua(Po,t),ua(Ro,e),ua(Lo,Ao),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:fe(null,"");break;default:t=fe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}ca(Lo),ua(Lo,t)}function Io(){ca(Lo),ca(Ro),ca(Po)}function Do(e){No(Po.current);var t=No(Lo.current),n=fe(t,e.type);t!==n&&(ua(Ro,e),ua(Lo,n))}function Mo(e){Ro.current===e&&(ca(Lo),ca(Ro))}var Fo=sa(0);function Bo(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.flags))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var jo=null,zo=null,Uo=!1;function $o(e,t){var n=Hs(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function qo(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Ho(e){if(Uo){var t=zo;if(t){var n=t;if(!qo(e,t)){if(!(t=Vr(n.nextSibling))||!qo(e,t))return e.flags=-1025&e.flags|2,Uo=!1,void(jo=e);$o(jo,n)}jo=e,zo=Vr(t.firstChild)}else e.flags=-1025&e.flags|2,Uo=!1,jo=e}}function Go(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;jo=e}function Zo(e){if(e!==jo)return!1;if(!Uo)return Go(e),Uo=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!qr(t,e.memoizedProps))for(t=zo;t;)$o(e,t),t=Vr(t.nextSibling);if(Go(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(i(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){zo=Vr(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}zo=null}}else zo=jo?Vr(e.stateNode.nextSibling):null;return!0}function Vo(){zo=jo=null,Uo=!1}var Wo=[];function Ko(){for(var e=0;e<Wo.length;e++)Wo[e]._workInProgressVersionPrimary=null;Wo.length=0}var Yo=k.ReactCurrentDispatcher,Qo=k.ReactCurrentBatchConfig,Xo=0,Jo=null,ei=null,ti=null,ni=!1,ri=!1;function ai(){throw Error(i(321))}function oi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!cr(e[n],t[n]))return!1;return!0}function ii(e,t,n,r,a,o){if(Xo=o,Jo=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,Yo.current=null===e||null===e.memoizedState?Ni:Oi,e=n(r,a),ri){o=0;do{if(ri=!1,!(25>o))throw Error(i(301));o+=1,ti=ei=null,t.updateQueue=null,Yo.current=Ii,e=n(r,a)}while(ri)}if(Yo.current=Pi,t=null!==ei&&null!==ei.next,Xo=0,ti=ei=Jo=null,ni=!1,t)throw Error(i(300));return e}function li(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===ti?Jo.memoizedState=ti=e:ti=ti.next=e,ti}function si(){if(null===ei){var e=Jo.alternate;e=null!==e?e.memoizedState:null}else e=ei.next;var t=null===ti?Jo.memoizedState:ti.next;if(null!==t)ti=t,ei=e;else{if(null===e)throw Error(i(310));e={memoizedState:(ei=e).memoizedState,baseState:ei.baseState,baseQueue:ei.baseQueue,queue:ei.queue,next:null},null===ti?Jo.memoizedState=ti=e:ti=ti.next=e}return ti}function ci(e,t){return"function"==typeof t?t(e):t}function ui(e){var t=si(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=ei,a=r.baseQueue,o=n.pending;if(null!==o){if(null!==a){var l=a.next;a.next=o.next,o.next=l}r.baseQueue=a=o,n.pending=null}if(null!==a){a=a.next,r=r.baseState;var s=l=o=null,c=a;do{var u=c.lane;if((Xo&u)===u)null!==s&&(s=s.next={lane:0,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null}),r=c.eagerReducer===e?c.eagerState:e(r,c.action);else{var d={lane:u,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null};null===s?(l=s=d,o=r):s=s.next=d,Jo.lanes|=u,Ul|=u}c=c.next}while(null!==c&&c!==a);null===s?o=r:s.next=l,cr(r,t.memoizedState)||(Mi=!0),t.memoizedState=r,t.baseState=o,t.baseQueue=s,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function di(e){var t=si(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,o=t.memoizedState;if(null!==a){n.pending=null;var l=a=a.next;do{o=e(o,l.action),l=l.next}while(l!==a);cr(o,t.memoizedState)||(Mi=!0),t.memoizedState=o,null===t.baseQueue&&(t.baseState=o),n.lastRenderedState=o}return[o,r]}function pi(e,t,n){var r=t._getVersion;r=r(t._source);var a=t._workInProgressVersionPrimary;if(null!==a?e=a===r:(e=e.mutableReadLanes,(e=(Xo&e)===e)&&(t._workInProgressVersionPrimary=r,Wo.push(t))),e)return n(t._source);throw Wo.push(t),Error(i(350))}function fi(e,t,n,r){var a=Ol;if(null===a)throw Error(i(349));var o=t._getVersion,l=o(t._source),s=Yo.current,c=s.useState((function(){return pi(a,t,n)})),u=c[1],d=c[0];c=ti;var p=e.memoizedState,f=p.refs,m=f.getSnapshot,h=p.source;p=p.subscribe;var g=Jo;return e.memoizedState={refs:f,source:t,subscribe:r},s.useEffect((function(){f.getSnapshot=n,f.setSnapshot=u;var e=o(t._source);if(!cr(l,e)){e=n(t._source),cr(d,e)||(u(e),e=fs(g),a.mutableReadLanes|=e&a.pendingLanes),e=a.mutableReadLanes,a.entangledLanes|=e;for(var r=a.entanglements,i=e;0<i;){var s=31-qt(i),c=1<<s;r[s]|=e,i&=~c}}}),[n,t,r]),s.useEffect((function(){return r(t._source,(function(){var e=f.getSnapshot,n=f.setSnapshot;try{n(e(t._source));var r=fs(g);a.mutableReadLanes|=r&a.pendingLanes}catch(o){n((function(){throw o}))}}))}),[t,r]),cr(m,n)&&cr(h,t)&&cr(p,r)||((e={pending:null,dispatch:null,lastRenderedReducer:ci,lastRenderedState:d}).dispatch=u=Ri.bind(null,Jo,e),c.queue=e,c.baseQueue=null,d=pi(a,t,n),c.memoizedState=c.baseState=d),d}function mi(e,t,n){return fi(si(),e,t,n)}function hi(e){var t=li();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:ci,lastRenderedState:e}).dispatch=Ri.bind(null,Jo,e),[t.memoizedState,e]}function gi(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=Jo.updateQueue)?(t={lastEffect:null},Jo.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function bi(e){return e={current:e},li().memoizedState=e}function vi(){return si().memoizedState}function yi(e,t,n,r){var a=li();Jo.flags|=e,a.memoizedState=gi(1|t,n,void 0,void 0===r?null:r)}function wi(e,t,n,r){var a=si();r=void 0===r?null:r;var o=void 0;if(null!==ei){var i=ei.memoizedState;if(o=i.destroy,null!==r&&oi(r,i.deps))return void gi(t,n,o,r)}Jo.flags|=e,a.memoizedState=gi(1|t,n,o,r)}function ki(e,t){return yi(516,4,e,t)}function _i(e,t){return wi(516,4,e,t)}function Ei(e,t){return wi(4,2,e,t)}function Si(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function xi(e,t,n){return n=null!=n?n.concat([e]):null,wi(4,2,Si.bind(null,t,e),n)}function Ci(){}function Ti(e,t){var n=si();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&oi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Ai(e,t){var n=si();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&oi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Li(e,t){var n=qa();Ga(98>n?98:n,(function(){e(!0)})),Ga(97<n?97:n,(function(){var n=Qo.transition;Qo.transition=1;try{e(!1),t()}finally{Qo.transition=n}}))}function Ri(e,t,n){var r=ps(),a=fs(e),o={lane:a,action:n,eagerReducer:null,eagerState:null,next:null},i=t.pending;if(null===i?o.next=o:(o.next=i.next,i.next=o),t.pending=o,i=e.alternate,e===Jo||null!==i&&i===Jo)ri=ni=!0;else{if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=t.lastRenderedReducer))try{var l=t.lastRenderedState,s=i(l,n);if(o.eagerReducer=i,o.eagerState=s,cr(s,l))return}catch(c){}ms(e,a,r)}}var Pi={readContext:oo,useCallback:ai,useContext:ai,useEffect:ai,useImperativeHandle:ai,useLayoutEffect:ai,useMemo:ai,useReducer:ai,useRef:ai,useState:ai,useDebugValue:ai,useDeferredValue:ai,useTransition:ai,useMutableSource:ai,useOpaqueIdentifier:ai,unstable_isNewReconciler:!1},Ni={readContext:oo,useCallback:function(e,t){return li().memoizedState=[e,void 0===t?null:t],e},useContext:oo,useEffect:ki,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,yi(4,2,Si.bind(null,t,e),n)},useLayoutEffect:function(e,t){return yi(4,2,e,t)},useMemo:function(e,t){var n=li();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=li();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=Ri.bind(null,Jo,e),[r.memoizedState,e]},useRef:bi,useState:hi,useDebugValue:Ci,useDeferredValue:function(e){var t=hi(e),n=t[0],r=t[1];return ki((function(){var t=Qo.transition;Qo.transition=1;try{r(e)}finally{Qo.transition=t}}),[e]),n},useTransition:function(){var e=hi(!1),t=e[0];return bi(e=Li.bind(null,e[1])),[e,t]},useMutableSource:function(e,t,n){var r=li();return r.memoizedState={refs:{getSnapshot:t,setSnapshot:null},source:e,subscribe:n},fi(r,e,t,n)},useOpaqueIdentifier:function(){if(Uo){var e=!1,t=function(e){return{$$typeof:D,toString:e,valueOf:e}}((function(){throw e||(e=!0,n("r:"+(Kr++).toString(36))),Error(i(355))})),n=hi(t)[1];return 0==(2&Jo.mode)&&(Jo.flags|=516,gi(5,(function(){n("r:"+(Kr++).toString(36))}),void 0,null)),t}return hi(t="r:"+(Kr++).toString(36)),t},unstable_isNewReconciler:!1},Oi={readContext:oo,useCallback:Ti,useContext:oo,useEffect:_i,useImperativeHandle:xi,useLayoutEffect:Ei,useMemo:Ai,useReducer:ui,useRef:vi,useState:function(){return ui(ci)},useDebugValue:Ci,useDeferredValue:function(e){var t=ui(ci),n=t[0],r=t[1];return _i((function(){var t=Qo.transition;Qo.transition=1;try{r(e)}finally{Qo.transition=t}}),[e]),n},useTransition:function(){var e=ui(ci)[0];return[vi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return ui(ci)[0]},unstable_isNewReconciler:!1},Ii={readContext:oo,useCallback:Ti,useContext:oo,useEffect:_i,useImperativeHandle:xi,useLayoutEffect:Ei,useMemo:Ai,useReducer:di,useRef:vi,useState:function(){return di(ci)},useDebugValue:Ci,useDeferredValue:function(e){var t=di(ci),n=t[0],r=t[1];return _i((function(){var t=Qo.transition;Qo.transition=1;try{r(e)}finally{Qo.transition=t}}),[e]),n},useTransition:function(){var e=di(ci)[0];return[vi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return di(ci)[0]},unstable_isNewReconciler:!1},Di=k.ReactCurrentOwner,Mi=!1;function Fi(e,t,n,r){t.child=null===e?To(t,null,n,r):Co(t,e.child,n,r)}function Bi(e,t,n,r,a){n=n.render;var o=t.ref;return ao(t,a),r=ii(e,t,n,r,o,a),null===e||Mi?(t.flags|=1,Fi(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,ol(e,t,a))}function ji(e,t,n,r,a,o){if(null===e){var i=n.type;return"function"!=typeof i||Gs(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Vs(n.type,null,r,t,t.mode,o)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=i,zi(e,t,i,r,a,o))}return i=e.child,0==(a&o)&&(a=i.memoizedProps,(n=null!==(n=n.compare)?n:dr)(a,r)&&e.ref===t.ref)?ol(e,t,o):(t.flags|=1,(e=Zs(i,r)).ref=t.ref,e.return=t,t.child=e)}function zi(e,t,n,r,a,o){if(null!==e&&dr(e.memoizedProps,r)&&e.ref===t.ref){if(Mi=!1,0==(o&a))return t.lanes=e.lanes,ol(e,t,o);0!=(16384&e.flags)&&(Mi=!0)}return qi(e,t,n,r,o)}function Ui(e,t,n){var r=t.pendingProps,a=r.children,o=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(4&t.mode))t.memoizedState={baseLanes:0},_s(t,n);else{if(0==(1073741824&n))return e=null!==o?o.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e},_s(t,e),null;t.memoizedState={baseLanes:0},_s(t,null!==o?o.baseLanes:n)}else null!==o?(r=o.baseLanes|n,t.memoizedState=null):r=n,_s(t,r);return Fi(e,t,a,n),t.child}function $i(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=128)}function qi(e,t,n,r,a){var o=ga(n)?ma:pa.current;return o=ha(t,o),ao(t,a),n=ii(e,t,n,r,o,a),null===e||Mi?(t.flags|=1,Fi(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,ol(e,t,a))}function Hi(e,t,n,r,a){if(ga(n)){var o=!0;wa(t)}else o=!1;if(ao(t,a),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),yo(t,n,r),ko(t,n,r,a),r=!0;else if(null===e){var i=t.stateNode,l=t.memoizedProps;i.props=l;var s=i.context,c=n.contextType;"object"==typeof c&&null!==c?c=oo(c):c=ha(t,c=ga(n)?ma:pa.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==r||s!==c)&&wo(t,i,r,c),io=!1;var p=t.memoizedState;i.state=p,fo(t,r,i,a),s=t.memoizedState,l!==r||p!==s||fa.current||io?("function"==typeof u&&(go(t,n,u,r),s=t.memoizedState),(l=io||vo(t,n,l,r,p,s,c))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(t.flags|=4)):("function"==typeof i.componentDidMount&&(t.flags|=4),t.memoizedProps=r,t.memoizedState=s),i.props=r,i.state=s,i.context=c,r=l):("function"==typeof i.componentDidMount&&(t.flags|=4),r=!1)}else{i=t.stateNode,so(e,t),l=t.memoizedProps,c=t.type===t.elementType?l:Ya(t.type,l),i.props=c,d=t.pendingProps,p=i.context,"object"==typeof(s=n.contextType)&&null!==s?s=oo(s):s=ha(t,s=ga(n)?ma:pa.current);var f=n.getDerivedStateFromProps;(u="function"==typeof f||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==d||p!==s)&&wo(t,i,r,s),io=!1,p=t.memoizedState,i.state=p,fo(t,r,i,a);var m=t.memoizedState;l!==d||p!==m||fa.current||io?("function"==typeof f&&(go(t,n,f,r),m=t.memoizedState),(c=io||vo(t,n,c,r,p,m,s))?(u||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,m,s),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,m,s)),"function"==typeof i.componentDidUpdate&&(t.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(t.flags|=256)):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),t.memoizedProps=r,t.memoizedState=m),i.props=r,i.state=m,i.context=s,r=c):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),r=!1)}return Gi(e,t,n,r,o,a)}function Gi(e,t,n,r,a,o){$i(e,t);var i=0!=(64&t.flags);if(!r&&!i)return a&&ka(t,n,!1),ol(e,t,o);r=t.stateNode,Di.current=t;var l=i&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&i?(t.child=Co(t,e.child,null,o),t.child=Co(t,null,l,o)):Fi(e,t,l,o),t.memoizedState=r.state,a&&ka(t,n,!0),t.child}function Zi(e){var t=e.stateNode;t.pendingContext?va(0,t.pendingContext,t.pendingContext!==t.context):t.context&&va(0,t.context,!1),Oo(e,t.containerInfo)}var Vi,Wi,Ki,Yi,Qi={dehydrated:null,retryLane:0};function Xi(e,t,n){var r,a=t.pendingProps,o=Fo.current,i=!1;return(r=0!=(64&t.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&o)),r?(i=!0,t.flags&=-65):null!==e&&null===e.memoizedState||void 0===a.fallback||!0===a.unstable_avoidThisFallback||(o|=1),ua(Fo,1&o),null===e?(void 0!==a.fallback&&Ho(t),e=a.children,o=a.fallback,i?(e=Ji(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Qi,e):"number"==typeof a.unstable_expectedLoadTime?(e=Ji(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Qi,t.lanes=33554432,e):((n=Ks({mode:"visible",children:e},t.mode,n,null)).return=t,t.child=n)):(e.memoizedState,i?(a=tl(e,t,a.children,a.fallback,n),i=t.child,o=e.child.memoizedState,i.memoizedState=null===o?{baseLanes:n}:{baseLanes:o.baseLanes|n},i.childLanes=e.childLanes&~n,t.memoizedState=Qi,a):(n=el(e,t,a.children,n),t.memoizedState=null,n))}function Ji(e,t,n,r){var a=e.mode,o=e.child;return t={mode:"hidden",children:t},0==(2&a)&&null!==o?(o.childLanes=0,o.pendingProps=t):o=Ks(t,a,0,null),n=Ws(n,a,r,null),o.return=e,n.return=e,o.sibling=n,e.child=o,n}function el(e,t,n,r){var a=e.child;return e=a.sibling,n=Zs(a,{mode:"visible",children:n}),0==(2&t.mode)&&(n.lanes=r),n.return=t,n.sibling=null,null!==e&&(e.nextEffect=null,e.flags=8,t.firstEffect=t.lastEffect=e),t.child=n}function tl(e,t,n,r,a){var o=t.mode,i=e.child;e=i.sibling;var l={mode:"hidden",children:n};return 0==(2&o)&&t.child!==i?((n=t.child).childLanes=0,n.pendingProps=l,null!==(i=n.lastEffect)?(t.firstEffect=n.firstEffect,t.lastEffect=i,i.nextEffect=null):t.firstEffect=t.lastEffect=null):n=Zs(i,l),null!==e?r=Zs(e,r):(r=Ws(r,o,a,null)).flags|=2,r.return=t,n.return=t,n.sibling=r,t.child=n,r}function nl(e,t){e.lanes|=t;var n=e.alternate;null!==n&&(n.lanes|=t),ro(e.return,t)}function rl(e,t,n,r,a,o){var i=e.memoizedState;null===i?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a,lastEffect:o}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=r,i.tail=n,i.tailMode=a,i.lastEffect=o)}function al(e,t,n){var r=t.pendingProps,a=r.revealOrder,o=r.tail;if(Fi(e,t,r.children,n),0!=(2&(r=Fo.current)))r=1&r|2,t.flags|=64;else{if(null!==e&&0!=(64&e.flags))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&nl(e,n);else if(19===e.tag)nl(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ua(Fo,r),0==(2&t.mode))t.memoizedState=null;else switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===Bo(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),rl(t,!1,a,n,o,t.lastEffect);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===Bo(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}rl(t,!0,n,null,o,t.lastEffect);break;case"together":rl(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}return t.child}function ol(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),Ul|=t.lanes,0!=(n&t.childLanes)){if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Zs(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Zs(e,e.pendingProps)).return=t;n.sibling=null}return t.child}return null}function il(e,t){if(!Uo)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ll(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return ga(t.type)&&ba(),null;case 3:return Io(),ca(fa),ca(pa),Ko(),(r=t.stateNode).pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(Zo(t)?t.flags|=4:r.hydrate||(t.flags|=256)),Wi(t),null;case 5:Mo(t);var o=No(Po.current);if(n=t.type,null!==e&&null!=t.stateNode)Ki(e,t,n,r,o),e.ref!==t.ref&&(t.flags|=128);else{if(!r){if(null===t.stateNode)throw Error(i(166));return null}if(e=No(Lo.current),Zo(t)){r=t.stateNode,n=t.type;var l=t.memoizedProps;switch(r[Qr]=t,r[Xr]=l,n){case"dialog":Lr("cancel",r),Lr("close",r);break;case"iframe":case"object":case"embed":Lr("load",r);break;case"video":case"audio":for(e=0;e<xr.length;e++)Lr(xr[e],r);break;case"source":Lr("error",r);break;case"img":case"image":case"link":Lr("error",r),Lr("load",r);break;case"details":Lr("toggle",r);break;case"input":ee(r,l),Lr("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!l.multiple},Lr("invalid",r);break;case"textarea":se(r,l),Lr("invalid",r)}for(var c in Ee(n,l),e=null,l)l.hasOwnProperty(c)&&(o=l[c],"children"===c?"string"==typeof o?r.textContent!==o&&(e=["children",o]):"number"==typeof o&&r.textContent!==""+o&&(e=["children",""+o]):s.hasOwnProperty(c)&&null!=o&&"onScroll"===c&&Lr("scroll",r));switch(n){case"input":Y(r),re(r,l,!0);break;case"textarea":Y(r),ue(r);break;case"select":case"option":break;default:"function"==typeof l.onClick&&(r.onclick=jr)}r=e,t.updateQueue=r,null!==r&&(t.flags|=4)}else{switch(c=9===o.nodeType?o:o.ownerDocument,e===de.html&&(e=pe(n)),e===de.html?"script"===n?((e=c.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=c.createElement(n,{is:r.is}):(e=c.createElement(n),"select"===n&&(c=e,r.multiple?c.multiple=!0:r.size&&(c.size=r.size))):e=c.createElementNS(e,n),e[Qr]=t,e[Xr]=r,Vi(e,t,!1,!1),t.stateNode=e,c=Se(n,r),n){case"dialog":Lr("cancel",e),Lr("close",e),o=r;break;case"iframe":case"object":case"embed":Lr("load",e),o=r;break;case"video":case"audio":for(o=0;o<xr.length;o++)Lr(xr[o],e);o=r;break;case"source":Lr("error",e),o=r;break;case"img":case"image":case"link":Lr("error",e),Lr("load",e),o=r;break;case"details":Lr("toggle",e),o=r;break;case"input":ee(e,r),o=J(e,r),Lr("invalid",e);break;case"option":o=oe(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},o=a({},r,{value:void 0}),Lr("invalid",e);break;case"textarea":se(e,r),o=le(e,r),Lr("invalid",e);break;default:o=r}Ee(n,o);var u=o;for(l in u)if(u.hasOwnProperty(l)){var d=u[l];"style"===l?ke(e,d):"dangerouslySetInnerHTML"===l?null!=(d=d?d.__html:void 0)&&ge(e,d):"children"===l?"string"==typeof d?("textarea"!==n||""!==d)&&be(e,d):"number"==typeof d&&be(e,""+d):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(s.hasOwnProperty(l)?null!=d&&"onScroll"===l&&Lr("scroll",e):null!=d&&w(e,l,d,c))}switch(n){case"input":Y(e),re(e,r,!1);break;case"textarea":Y(e),ue(e);break;case"option":null!=r.value&&e.setAttribute("value",""+W(r.value));break;case"select":e.multiple=!!r.multiple,null!=(l=r.value)?ie(e,!!r.multiple,l,!1):null!=r.defaultValue&&ie(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof o.onClick&&(e.onclick=jr)}$r(n,r)&&(t.flags|=4)}null!==t.ref&&(t.flags|=128)}return null;case 6:if(e&&null!=t.stateNode)Yi(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(i(166));n=No(Po.current),No(Lo.current),Zo(t)?(r=t.stateNode,n=t.memoizedProps,r[Qr]=t,r.nodeValue!==n&&(t.flags|=4)):((r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[Qr]=t,t.stateNode=r)}return null;case 13:return ca(Fo),r=t.memoizedState,0!=(64&t.flags)?(t.lanes=n,t):(r=null!==r,n=!1,null===e?void 0!==t.memoizedProps.fallback&&Zo(t):n=null!==e.memoizedState,r&&!n&&0!=(2&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&Fo.current)?0===Bl&&(Bl=3):(0!==Bl&&3!==Bl||(Bl=4),null===Ol||0==(134217727&Ul)&&0==(134217727&$l)||vs(Ol,Dl))),(r||n)&&(t.flags|=4),null);case 4:return Io(),Wi(t),null===e&&Pr(t.stateNode.containerInfo),null;case 10:return no(t),null;case 19:if(ca(Fo),null===(r=t.memoizedState))return null;if(l=0!=(64&t.flags),null===(c=r.rendering))if(l)il(r,!1);else{if(0!==Bl||null!==e&&0!=(64&e.flags))for(e=t.child;null!==e;){if(null!==(c=Bo(e))){for(t.flags|=64,il(r,!1),null!==(l=c.updateQueue)&&(t.updateQueue=l,t.flags|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=n,n=t.child;null!==n;)e=r,(l=n).flags&=2,l.nextEffect=null,l.firstEffect=null,l.lastEffect=null,null===(c=l.alternate)?(l.childLanes=0,l.lanes=e,l.child=null,l.memoizedProps=null,l.memoizedState=null,l.updateQueue=null,l.dependencies=null,l.stateNode=null):(l.childLanes=c.childLanes,l.lanes=c.lanes,l.child=c.child,l.memoizedProps=c.memoizedProps,l.memoizedState=c.memoizedState,l.updateQueue=c.updateQueue,l.type=c.type,e=c.dependencies,l.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return ua(Fo,1&Fo.current|2),t.child}e=e.sibling}null!==r.tail&&$a()>Zl&&(t.flags|=64,l=!0,il(r,!1),t.lanes=33554432)}else{if(!l)if(null!==(e=Bo(c))){if(t.flags|=64,l=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),il(r,!0),null===r.tail&&"hidden"===r.tailMode&&!c.alternate&&!Uo)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*$a()-r.renderingStartTime>Zl&&1073741824!==n&&(t.flags|=64,l=!0,il(r,!1),t.lanes=33554432);r.isBackwards?(c.sibling=t.child,t.child=c):(null!==(n=r.last)?n.sibling=c:t.child=c,r.last=c)}return null!==r.tail?(n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=$a(),n.sibling=null,t=Fo.current,ua(Fo,l?1&t|2:1&t),n):null;case 23:case 24:return Es(),null!==e&&null!==e.memoizedState!=(null!==t.memoizedState)&&"unstable-defer-without-hiding"!==r.mode&&(t.flags|=4),null}throw Error(i(156,t.tag))}function sl(e){switch(e.tag){case 1:ga(e.type)&&ba();var t=e.flags;return 4096&t?(e.flags=-4097&t|64,e):null;case 3:if(Io(),ca(fa),ca(pa),Ko(),0!=(64&(t=e.flags)))throw Error(i(285));return e.flags=-4097&t|64,e;case 5:return Mo(e),null;case 13:return ca(Fo),4096&(t=e.flags)?(e.flags=-4097&t|64,e):null;case 19:return ca(Fo),null;case 4:return Io(),null;case 10:return no(e),null;case 23:case 24:return Es(),null;default:return null}}function cl(e,t){try{var n="",r=t;do{n+=Z(r),r=r.return}while(r);var a=n}catch(o){a="\nError generating stack: "+o.message+"\n"+o.stack}return{value:e,source:t,stack:a}}function ul(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}Vi=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Wi=function(){},Ki=function(e,t,n,r){var o=e.memoizedProps;if(o!==r){e=t.stateNode,No(Lo.current);var i,l=null;switch(n){case"input":o=J(e,o),r=J(e,r),l=[];break;case"option":o=oe(e,o),r=oe(e,r),l=[];break;case"select":o=a({},o,{value:void 0}),r=a({},r,{value:void 0}),l=[];break;case"textarea":o=le(e,o),r=le(e,r),l=[];break;default:"function"!=typeof o.onClick&&"function"==typeof r.onClick&&(e.onclick=jr)}for(d in Ee(n,r),n=null,o)if(!r.hasOwnProperty(d)&&o.hasOwnProperty(d)&&null!=o[d])if("style"===d){var c=o[d];for(i in c)c.hasOwnProperty(i)&&(n||(n={}),n[i]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(s.hasOwnProperty(d)?l||(l=[]):(l=l||[]).push(d,null));for(d in r){var u=r[d];if(c=null!=o?o[d]:void 0,r.hasOwnProperty(d)&&u!==c&&(null!=u||null!=c))if("style"===d)if(c){for(i in c)!c.hasOwnProperty(i)||u&&u.hasOwnProperty(i)||(n||(n={}),n[i]="");for(i in u)u.hasOwnProperty(i)&&c[i]!==u[i]&&(n||(n={}),n[i]=u[i])}else n||(l||(l=[]),l.push(d,n)),n=u;else"dangerouslySetInnerHTML"===d?(u=u?u.__html:void 0,c=c?c.__html:void 0,null!=u&&c!==u&&(l=l||[]).push(d,u)):"children"===d?"string"!=typeof u&&"number"!=typeof u||(l=l||[]).push(d,""+u):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(s.hasOwnProperty(d)?(null!=u&&"onScroll"===d&&Lr("scroll",e),l||c===u||(l=[])):"object"==typeof u&&null!==u&&u.$$typeof===D?u.toString():(l=l||[]).push(d,u))}n&&(l=l||[]).push("style",n);var d=l;(t.updateQueue=d)&&(t.flags|=4)}},Yi=function(e,t,n,r){n!==r&&(t.flags|=4)};var dl="function"==typeof WeakMap?WeakMap:Map;function pl(e,t,n){(n=co(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Yl||(Yl=!0,Ql=r),ul(0,t)},n}function fl(e,t,n){(n=co(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return ul(0,t),r(a)}}var o=e.stateNode;return null!==o&&"function"==typeof o.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===Xl?Xl=new Set([this]):Xl.add(this),ul(0,t));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}var ml="function"==typeof WeakSet?WeakSet:Set;function hl(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){zs(e,n)}else t.current=null}function gl(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 5:case 6:case 4:case 17:return;case 1:if(256&t.flags&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:Ya(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return;case 3:return void(256&t.flags&&Zr(t.stateNode.containerInfo))}throw Error(i(163))}function bl(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{if(3==(3&e.tag)){var r=e.create;e.destroy=r()}e=e.next}while(e!==t)}if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{var a=e;r=a.next,0!=(4&(a=a.tag))&&0!=(1&a)&&(Fs(n,e),Ms(n,e)),e=r}while(e!==t)}return;case 1:return e=n.stateNode,4&n.flags&&(null===t?e.componentDidMount():(r=n.elementType===n.type?t.memoizedProps:Ya(n.type,t.memoizedProps),e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate))),void(null!==(t=n.updateQueue)&&mo(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}mo(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.flags&&$r(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:case 23:case 24:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&kt(n)))))}throw Error(i(163))}function vl(e,t){for(var n=e;;){if(5===n.tag){var r=n.stateNode;if(t)"function"==typeof(r=r.style).setProperty?r.setProperty("display","none","important"):r.display="none";else{r=n.stateNode;var a=n.memoizedProps.style;a=null!=a&&a.hasOwnProperty("display")?a.display:null,r.style.display=we("display",a)}}else if(6===n.tag)n.stateNode.nodeValue=t?"":n.memoizedProps;else if((23!==n.tag&&24!==n.tag||null===n.memoizedState||n===e)&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return;n=n.return}n.sibling.return=n.return,n=n.sibling}}function yl(e,t){if(Ea&&"function"==typeof Ea.onCommitFiberUnmount)try{Ea.onCommitFiberUnmount(_a,t)}catch(o){}switch(t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var n=e=e.next;do{var r=n,a=r.destroy;if(r=r.tag,void 0!==a)if(0!=(4&r))Fs(t,n);else{r=t;try{a()}catch(o){zs(r,o)}}n=n.next}while(n!==e)}break;case 1:if(hl(t),"function"==typeof(e=t.stateNode).componentWillUnmount)try{e.props=t.memoizedProps,e.state=t.memoizedState,e.componentWillUnmount()}catch(o){zs(t,o)}break;case 5:hl(t);break;case 4:xl(e,t)}}function wl(e){e.alternate=null,e.child=null,e.dependencies=null,e.firstEffect=null,e.lastEffect=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.return=null,e.updateQueue=null}function kl(e){return 5===e.tag||3===e.tag||4===e.tag}function _l(e){e:{for(var t=e.return;null!==t;){if(kl(t))break e;t=t.return}throw Error(i(160))}var n=t;switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(i(161))}16&n.flags&&(be(t,""),n.flags&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||kl(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.flags)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.flags)){n=n.stateNode;break e}}r?El(e,n,t):Sl(e,n,t)}function El(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=jr));else if(4!==r&&null!==(e=e.child))for(El(e,t,n),e=e.sibling;null!==e;)El(e,t,n),e=e.sibling}function Sl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(Sl(e,t,n),e=e.sibling;null!==e;)Sl(e,t,n),e=e.sibling}function xl(e,t){for(var n,r,a=t,o=!1;;){if(!o){o=a.return;e:for(;;){if(null===o)throw Error(i(160));switch(n=o.stateNode,o.tag){case 5:r=!1;break e;case 3:case 4:n=n.containerInfo,r=!0;break e}o=o.return}o=!0}if(5===a.tag||6===a.tag){e:for(var l=e,s=a,c=s;;)if(yl(l,c),null!==c.child&&4!==c.tag)c.child.return=c,c=c.child;else{if(c===s)break e;for(;null===c.sibling;){if(null===c.return||c.return===s)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}r?(l=n,s=a.stateNode,8===l.nodeType?l.parentNode.removeChild(s):l.removeChild(s)):n.removeChild(a.stateNode)}else if(4===a.tag){if(null!==a.child){n=a.stateNode.containerInfo,r=!0,a.child.return=a,a=a.child;continue}}else if(yl(e,a),null!==a.child){a.child.return=a,a=a.child;continue}if(a===t)break;for(;null===a.sibling;){if(null===a.return||a.return===t)return;4===(a=a.return).tag&&(o=!1)}a.sibling.return=a.return,a=a.sibling}}function Cl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:var n=t.updateQueue;if(null!==(n=null!==n?n.lastEffect:null)){var r=n=n.next;do{3==(3&r.tag)&&(e=r.destroy,r.destroy=void 0,void 0!==e&&e()),r=r.next}while(r!==n)}return;case 1:case 12:case 17:return;case 5:if(null!=(n=t.stateNode)){r=t.memoizedProps;var a=null!==e?e.memoizedProps:r;e=t.type;var o=t.updateQueue;if(t.updateQueue=null,null!==o){for(n[Xr]=r,"input"===e&&"radio"===r.type&&null!=r.name&&te(n,r),Se(e,a),t=Se(e,r),a=0;a<o.length;a+=2){var l=o[a],s=o[a+1];"style"===l?ke(n,s):"dangerouslySetInnerHTML"===l?ge(n,s):"children"===l?be(n,s):w(n,l,s,t)}switch(e){case"input":ne(n,r);break;case"textarea":ce(n,r);break;case"select":e=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(o=r.value)?ie(n,!!r.multiple,o,!1):e!==!!r.multiple&&(null!=r.defaultValue?ie(n,!!r.multiple,r.defaultValue,!0):ie(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(i(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((n=t.stateNode).hydrate&&(n.hydrate=!1,kt(n.containerInfo)));case 13:return null!==t.memoizedState&&(Gl=$a(),vl(t.child,!0)),void Tl(t);case 19:return void Tl(t);case 23:case 24:return void vl(t,null!==t.memoizedState)}throw Error(i(163))}function Tl(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new ml),t.forEach((function(t){var r=$s.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function Al(e,t){return null!==e&&(null===(e=e.memoizedState)||null!==e.dehydrated)&&(null!==(t=t.memoizedState)&&null===t.dehydrated)}var Ll=Math.ceil,Rl=k.ReactCurrentDispatcher,Pl=k.ReactCurrentOwner,Nl=0,Ol=null,Il=null,Dl=0,Ml=0,Fl=sa(0),Bl=0,jl=null,zl=0,Ul=0,$l=0,ql=0,Hl=null,Gl=0,Zl=1/0;function Vl(){Zl=$a()+500}var Wl,Kl=null,Yl=!1,Ql=null,Xl=null,Jl=!1,es=null,ts=90,ns=[],rs=[],as=null,os=0,is=null,ls=-1,ss=0,cs=0,us=null,ds=!1;function ps(){return 0!=(48&Nl)?$a():-1!==ls?ls:ls=$a()}function fs(e){if(0==(2&(e=e.mode)))return 1;if(0==(4&e))return 99===qa()?1:2;if(0===ss&&(ss=zl),0!==Ka.transition){0!==cs&&(cs=null!==Hl?Hl.pendingLanes:0),e=ss;var t=4186112&~cs;return 0===(t&=-t)&&(0===(t=(e=4186112&~e)&-e)&&(t=8192)),t}return e=qa(),0!=(4&Nl)&&98===e?e=jt(12,ss):e=jt(e=function(e){switch(e){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}(e),ss),e}function ms(e,t,n){if(50<os)throw os=0,is=null,Error(i(185));if(null===(e=hs(e,t)))return null;$t(e,t,n),e===Ol&&($l|=t,4===Bl&&vs(e,Dl));var r=qa();1===t?0!=(8&Nl)&&0==(48&Nl)?ys(e):(gs(e,n),0===Nl&&(Vl(),Va())):(0==(4&Nl)||98!==r&&99!==r||(null===as?as=new Set([e]):as.add(e)),gs(e,n)),Hl=e}function hs(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}function gs(e,t){for(var n=e.callbackNode,r=e.suspendedLanes,a=e.pingedLanes,o=e.expirationTimes,l=e.pendingLanes;0<l;){var s=31-qt(l),c=1<<s,u=o[s];if(-1===u){if(0==(c&r)||0!=(c&a)){u=t,Mt(c);var d=Dt;o[s]=10<=d?u+250:6<=d?u+5e3:-1}}else u<=t&&(e.expiredLanes|=c);l&=~c}if(r=Ft(e,e===Ol?Dl:0),t=Dt,0===r)null!==n&&(n!==Ma&&Ca(n),e.callbackNode=null,e.callbackPriority=0);else{if(null!==n){if(e.callbackPriority===t)return;n!==Ma&&Ca(n)}15===t?(n=ys.bind(null,e),null===Ba?(Ba=[n],ja=xa(Pa,Wa)):Ba.push(n),n=Ma):14===t?n=Za(99,ys.bind(null,e)):(n=function(e){switch(e){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(i(358,e))}}(t),n=Za(n,bs.bind(null,e))),e.callbackPriority=t,e.callbackNode=n}}function bs(e){if(ls=-1,cs=ss=0,0!=(48&Nl))throw Error(i(327));var t=e.callbackNode;if(Ds()&&e.callbackNode!==t)return null;var n=Ft(e,e===Ol?Dl:0);if(0===n)return null;var r=n,a=Nl;Nl|=16;var o=Cs();for(Ol===e&&Dl===r||(Vl(),Ss(e,r));;)try{Ls();break}catch(s){xs(e,s)}if(to(),Rl.current=o,Nl=a,null!==Il?r=0:(Ol=null,Dl=0,r=Bl),0!=(zl&$l))Ss(e,0);else if(0!==r){if(2===r&&(Nl|=64,e.hydrate&&(e.hydrate=!1,Zr(e.containerInfo)),0!==(n=Bt(e))&&(r=Ts(e,n))),1===r)throw t=jl,Ss(e,0),vs(e,n),gs(e,$a()),t;switch(e.finishedWork=e.current.alternate,e.finishedLanes=n,r){case 0:case 1:throw Error(i(345));case 2:case 5:Ns(e);break;case 3:if(vs(e,n),(62914560&n)===n&&10<(r=Gl+500-$a())){if(0!==Ft(e,0))break;if(((a=e.suspendedLanes)&n)!==n){ps(),e.pingedLanes|=e.suspendedLanes&a;break}e.timeoutHandle=Hr(Ns.bind(null,e),r);break}Ns(e);break;case 4:if(vs(e,n),(4186112&n)===n)break;for(r=e.eventTimes,a=-1;0<n;){var l=31-qt(n);o=1<<l,(l=r[l])>a&&(a=l),n&=~o}if(n=a,10<(n=(120>(n=$a()-n)?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*Ll(n/1960))-n)){e.timeoutHandle=Hr(Ns.bind(null,e),n);break}Ns(e);break;default:throw Error(i(329))}}return gs(e,$a()),e.callbackNode===t?bs.bind(null,e):null}function vs(e,t){for(t&=~ql,t&=~$l,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-qt(t),r=1<<n;e[n]=-1,t&=~r}}function ys(e){if(0!=(48&Nl))throw Error(i(327));if(Ds(),e===Ol&&0!=(e.expiredLanes&Dl)){var t=Dl,n=Ts(e,t);0!=(zl&$l)&&(n=Ts(e,t=Ft(e,t)))}else n=Ts(e,t=Ft(e,0));if(0!==e.tag&&2===n&&(Nl|=64,e.hydrate&&(e.hydrate=!1,Zr(e.containerInfo)),0!==(t=Bt(e))&&(n=Ts(e,t))),1===n)throw n=jl,Ss(e,0),vs(e,t),gs(e,$a()),n;return e.finishedWork=e.current.alternate,e.finishedLanes=t,Ns(e),gs(e,$a()),null}function ws(e,t){var n=Nl;Nl|=1;try{return e(t)}finally{0===(Nl=n)&&(Vl(),Va())}}function ks(e,t){var n=Nl;Nl&=-2,Nl|=8;try{return e(t)}finally{0===(Nl=n)&&(Vl(),Va())}}function _s(e,t){ua(Fl,Ml),Ml|=t,zl|=t}function Es(){Ml=Fl.current,ca(Fl)}function Ss(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,Gr(n)),null!==Il)for(n=Il.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&ba();break;case 3:Io(),ca(fa),ca(pa),Ko();break;case 5:Mo(r);break;case 4:Io();break;case 13:case 19:ca(Fo);break;case 10:no(r);break;case 23:case 24:Es()}n=n.return}Ol=e,Il=Zs(e.current,null),Dl=Ml=zl=t,Bl=0,jl=null,ql=$l=Ul=0}function xs(e,t){for(;;){var n=Il;try{if(to(),Yo.current=Pi,ni){for(var r=Jo.memoizedState;null!==r;){var a=r.queue;null!==a&&(a.pending=null),r=r.next}ni=!1}if(Xo=0,ti=ei=Jo=null,ri=!1,Pl.current=null,null===n||null===n.return){Bl=1,jl=t,Il=null;break}e:{var o=e,i=n.return,l=n,s=t;if(t=Dl,l.flags|=2048,l.firstEffect=l.lastEffect=null,null!==s&&"object"==typeof s&&"function"==typeof s.then){var c=s;if(0==(2&l.mode)){var u=l.alternate;u?(l.updateQueue=u.updateQueue,l.memoizedState=u.memoizedState,l.lanes=u.lanes):(l.updateQueue=null,l.memoizedState=null)}var d=0!=(1&Fo.current),p=i;do{var f;if(f=13===p.tag){var m=p.memoizedState;if(null!==m)f=null!==m.dehydrated;else{var h=p.memoizedProps;f=void 0!==h.fallback&&(!0!==h.unstable_avoidThisFallback||!d)}}if(f){var g=p.updateQueue;if(null===g){var b=new Set;b.add(c),p.updateQueue=b}else g.add(c);if(0==(2&p.mode)){if(p.flags|=64,l.flags|=16384,l.flags&=-2981,1===l.tag)if(null===l.alternate)l.tag=17;else{var v=co(-1,1);v.tag=2,uo(l,v)}l.lanes|=1;break e}s=void 0,l=t;var y=o.pingCache;if(null===y?(y=o.pingCache=new dl,s=new Set,y.set(c,s)):void 0===(s=y.get(c))&&(s=new Set,y.set(c,s)),!s.has(l)){s.add(l);var w=Us.bind(null,o,c,l);c.then(w,w)}p.flags|=4096,p.lanes=t;break e}p=p.return}while(null!==p);s=Error((V(l.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.")}5!==Bl&&(Bl=2),s=cl(s,l),p=i;do{switch(p.tag){case 3:o=s,p.flags|=4096,t&=-t,p.lanes|=t,po(p,pl(0,o,t));break e;case 1:o=s;var k=p.type,_=p.stateNode;if(0==(64&p.flags)&&("function"==typeof k.getDerivedStateFromError||null!==_&&"function"==typeof _.componentDidCatch&&(null===Xl||!Xl.has(_)))){p.flags|=4096,t&=-t,p.lanes|=t,po(p,fl(p,o,t));break e}}p=p.return}while(null!==p)}Ps(n)}catch(E){t=E,Il===n&&null!==n&&(Il=n=n.return);continue}break}}function Cs(){var e=Rl.current;return Rl.current=Pi,null===e?Pi:e}function Ts(e,t){var n=Nl;Nl|=16;var r=Cs();for(Ol===e&&Dl===t||Ss(e,t);;)try{As();break}catch(a){xs(e,a)}if(to(),Nl=n,Rl.current=r,null!==Il)throw Error(i(261));return Ol=null,Dl=0,Bl}function As(){for(;null!==Il;)Rs(Il)}function Ls(){for(;null!==Il&&!Ta();)Rs(Il)}function Rs(e){var t=Wl(e.alternate,e,Ml);e.memoizedProps=e.pendingProps,null===t?Ps(e):Il=t,Pl.current=null}function Ps(e){var t=e;do{var n=t.alternate;if(e=t.return,0==(2048&t.flags)){if(null!==(n=ll(n,t,Ml)))return void(Il=n);if(24!==(n=t).tag&&23!==n.tag||null===n.memoizedState||0!=(1073741824&Ml)||0==(4&n.mode)){for(var r=0,a=n.child;null!==a;)r|=a.lanes|a.childLanes,a=a.sibling;n.childLanes=r}null!==e&&0==(2048&e.flags)&&(null===e.firstEffect&&(e.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1<t.flags&&(null!==e.lastEffect?e.lastEffect.nextEffect=t:e.firstEffect=t,e.lastEffect=t))}else{if(null!==(n=sl(t)))return n.flags&=2047,void(Il=n);null!==e&&(e.firstEffect=e.lastEffect=null,e.flags|=2048)}if(null!==(t=t.sibling))return void(Il=t);Il=t=e}while(null!==t);0===Bl&&(Bl=5)}function Ns(e){var t=qa();return Ga(99,Os.bind(null,e,t)),null}function Os(e,t){do{Ds()}while(null!==es);if(0!=(48&Nl))throw Error(i(327));var n=e.finishedWork;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(i(177));e.callbackNode=null;var r=n.lanes|n.childLanes,a=r,o=e.pendingLanes&~a;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=a,e.mutableReadLanes&=a,e.entangledLanes&=a,a=e.entanglements;for(var l=e.eventTimes,s=e.expirationTimes;0<o;){var c=31-qt(o),u=1<<c;a[c]=0,l[c]=-1,s[c]=-1,o&=~u}if(null!==as&&0==(24&r)&&as.has(e)&&as.delete(e),e===Ol&&(Il=Ol=null,Dl=0),1<n.flags?null!==n.lastEffect?(n.lastEffect.nextEffect=n,r=n.firstEffect):r=n:r=n.firstEffect,null!==r){if(a=Nl,Nl|=32,Pl.current=null,zr=Wt,gr(l=hr())){if("selectionStart"in l)s={start:l.selectionStart,end:l.selectionEnd};else e:if(s=(s=l.ownerDocument)&&s.defaultView||window,(u=s.getSelection&&s.getSelection())&&0!==u.rangeCount){s=u.anchorNode,o=u.anchorOffset,c=u.focusNode,u=u.focusOffset;try{s.nodeType,c.nodeType}catch(C){s=null;break e}var d=0,p=-1,f=-1,m=0,h=0,g=l,b=null;t:for(;;){for(var v;g!==s||0!==o&&3!==g.nodeType||(p=d+o),g!==c||0!==u&&3!==g.nodeType||(f=d+u),3===g.nodeType&&(d+=g.nodeValue.length),null!==(v=g.firstChild);)b=g,g=v;for(;;){if(g===l)break t;if(b===s&&++m===o&&(p=d),b===c&&++h===u&&(f=d),null!==(v=g.nextSibling))break;b=(g=b).parentNode}g=v}s=-1===p||-1===f?null:{start:p,end:f}}else s=null;s=s||{start:0,end:0}}else s=null;Ur={focusedElem:l,selectionRange:s},Wt=!1,us=null,ds=!1,Kl=r;do{try{Is()}catch(C){if(null===Kl)throw Error(i(330));zs(Kl,C),Kl=Kl.nextEffect}}while(null!==Kl);us=null,Kl=r;do{try{for(l=e;null!==Kl;){var y=Kl.flags;if(16&y&&be(Kl.stateNode,""),128&y){var w=Kl.alternate;if(null!==w){var k=w.ref;null!==k&&("function"==typeof k?k(null):k.current=null)}}switch(1038&y){case 2:_l(Kl),Kl.flags&=-3;break;case 6:_l(Kl),Kl.flags&=-3,Cl(Kl.alternate,Kl);break;case 1024:Kl.flags&=-1025;break;case 1028:Kl.flags&=-1025,Cl(Kl.alternate,Kl);break;case 4:Cl(Kl.alternate,Kl);break;case 8:xl(l,s=Kl);var _=s.alternate;wl(s),null!==_&&wl(_)}Kl=Kl.nextEffect}}catch(C){if(null===Kl)throw Error(i(330));zs(Kl,C),Kl=Kl.nextEffect}}while(null!==Kl);if(k=Ur,w=hr(),y=k.focusedElem,l=k.selectionRange,w!==y&&y&&y.ownerDocument&&mr(y.ownerDocument.documentElement,y)){null!==l&&gr(y)&&(w=l.start,void 0===(k=l.end)&&(k=w),"selectionStart"in y?(y.selectionStart=w,y.selectionEnd=Math.min(k,y.value.length)):(k=(w=y.ownerDocument||document)&&w.defaultView||window).getSelection&&(k=k.getSelection(),s=y.textContent.length,_=Math.min(l.start,s),l=void 0===l.end?_:Math.min(l.end,s),!k.extend&&_>l&&(s=l,l=_,_=s),s=fr(y,_),o=fr(y,l),s&&o&&(1!==k.rangeCount||k.anchorNode!==s.node||k.anchorOffset!==s.offset||k.focusNode!==o.node||k.focusOffset!==o.offset)&&((w=w.createRange()).setStart(s.node,s.offset),k.removeAllRanges(),_>l?(k.addRange(w),k.extend(o.node,o.offset)):(w.setEnd(o.node,o.offset),k.addRange(w))))),w=[];for(k=y;k=k.parentNode;)1===k.nodeType&&w.push({element:k,left:k.scrollLeft,top:k.scrollTop});for("function"==typeof y.focus&&y.focus(),y=0;y<w.length;y++)(k=w[y]).element.scrollLeft=k.left,k.element.scrollTop=k.top}Wt=!!zr,Ur=zr=null,e.current=n,Kl=r;do{try{for(y=e;null!==Kl;){var E=Kl.flags;if(36&E&&bl(y,Kl.alternate,Kl),128&E){w=void 0;var S=Kl.ref;if(null!==S){var x=Kl.stateNode;Kl.tag,w=x,"function"==typeof S?S(w):S.current=w}}Kl=Kl.nextEffect}}catch(C){if(null===Kl)throw Error(i(330));zs(Kl,C),Kl=Kl.nextEffect}}while(null!==Kl);Kl=null,Fa(),Nl=a}else e.current=n;if(Jl)Jl=!1,es=e,ts=t;else for(Kl=r;null!==Kl;)t=Kl.nextEffect,Kl.nextEffect=null,8&Kl.flags&&((E=Kl).sibling=null,E.stateNode=null),Kl=t;if(0===(r=e.pendingLanes)&&(Xl=null),1===r?e===is?os++:(os=0,is=e):os=0,n=n.stateNode,Ea&&"function"==typeof Ea.onCommitFiberRoot)try{Ea.onCommitFiberRoot(_a,n,void 0,64==(64&n.current.flags))}catch(C){}if(gs(e,$a()),Yl)throw Yl=!1,e=Ql,Ql=null,e;return 0!=(8&Nl)||Va(),null}function Is(){for(;null!==Kl;){var e=Kl.alternate;ds||null===us||(0!=(8&Kl.flags)?Je(Kl,us)&&(ds=!0):13===Kl.tag&&Al(e,Kl)&&Je(Kl,us)&&(ds=!0));var t=Kl.flags;0!=(256&t)&&gl(e,Kl),0==(512&t)||Jl||(Jl=!0,Za(97,(function(){return Ds(),null}))),Kl=Kl.nextEffect}}function Ds(){if(90!==ts){var e=97<ts?97:ts;return ts=90,Ga(e,Bs)}return!1}function Ms(e,t){ns.push(t,e),Jl||(Jl=!0,Za(97,(function(){return Ds(),null})))}function Fs(e,t){rs.push(t,e),Jl||(Jl=!0,Za(97,(function(){return Ds(),null})))}function Bs(){if(null===es)return!1;var e=es;if(es=null,0!=(48&Nl))throw Error(i(331));var t=Nl;Nl|=32;var n=rs;rs=[];for(var r=0;r<n.length;r+=2){var a=n[r],o=n[r+1],l=a.destroy;if(a.destroy=void 0,"function"==typeof l)try{l()}catch(c){if(null===o)throw Error(i(330));zs(o,c)}}for(n=ns,ns=[],r=0;r<n.length;r+=2){a=n[r],o=n[r+1];try{var s=a.create;a.destroy=s()}catch(c){if(null===o)throw Error(i(330));zs(o,c)}}for(s=e.current.firstEffect;null!==s;)e=s.nextEffect,s.nextEffect=null,8&s.flags&&(s.sibling=null,s.stateNode=null),s=e;return Nl=t,Va(),!0}function js(e,t,n){uo(e,t=pl(0,t=cl(n,t),1)),t=ps(),null!==(e=hs(e,1))&&($t(e,1,t),gs(e,t))}function zs(e,t){if(3===e.tag)js(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){js(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Xl||!Xl.has(r))){var a=fl(n,e=cl(t,e),1);if(uo(n,a),a=ps(),null!==(n=hs(n,1)))$t(n,1,a),gs(n,a);else if("function"==typeof r.componentDidCatch&&(null===Xl||!Xl.has(r)))try{r.componentDidCatch(t,e)}catch(o){}break}}n=n.return}}function Us(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=ps(),e.pingedLanes|=e.suspendedLanes&n,Ol===e&&(Dl&n)===n&&(4===Bl||3===Bl&&(62914560&Dl)===Dl&&500>$a()-Gl?Ss(e,0):ql|=n),gs(e,t)}function $s(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(0==(2&(t=e.mode))?t=1:0==(4&t)?t=99===qa()?1:2:(0===ss&&(ss=zl),0===(t=zt(62914560&~ss))&&(t=4194304))),n=ps(),null!==(e=hs(e,t))&&($t(e,t,n),gs(e,n))}function qs(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Hs(e,t,n,r){return new qs(e,t,n,r)}function Gs(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Zs(e,t){var n=e.alternate;return null===n?((n=Hs(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Vs(e,t,n,r,a,o){var l=2;if(r=e,"function"==typeof e)Gs(e)&&(l=1);else if("string"==typeof e)l=5;else e:switch(e){case S:return Ws(n.children,a,o,t);case M:l=8,a|=16;break;case x:l=8,a|=1;break;case C:return(e=Hs(12,n,t,8|a)).elementType=C,e.type=C,e.lanes=o,e;case R:return(e=Hs(13,n,t,a)).type=R,e.elementType=R,e.lanes=o,e;case P:return(e=Hs(19,n,t,a)).elementType=P,e.lanes=o,e;case F:return Ks(n,a,o,t);case B:return(e=Hs(24,n,t,a)).elementType=B,e.lanes=o,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case T:l=10;break e;case A:l=9;break e;case L:l=11;break e;case N:l=14;break e;case O:l=16,r=null;break e;case I:l=22;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Hs(l,n,t,a)).elementType=e,t.type=r,t.lanes=o,t}function Ws(e,t,n,r){return(e=Hs(7,e,r,t)).lanes=n,e}function Ks(e,t,n,r){return(e=Hs(23,e,r,t)).elementType=F,e.lanes=n,e}function Ys(e,t,n){return(e=Hs(6,e,null,t)).lanes=n,e}function Qs(e,t,n){return(t=Hs(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Xs(e,t,n){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=Ut(0),this.expirationTimes=Ut(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Ut(0),this.mutableSourceEagerHydrationData=null}function Js(e,t,n,r){var a=t.current,o=ps(),l=fs(a);e:if(n){t:{if(Ke(n=n._reactInternals)!==n||1!==n.tag)throw Error(i(170));var s=n;do{switch(s.tag){case 3:s=s.stateNode.context;break t;case 1:if(ga(s.type)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break t}}s=s.return}while(null!==s);throw Error(i(171))}if(1===n.tag){var c=n.type;if(ga(c)){n=ya(n,c,s);break e}}n=s}else n=da;return null===t.context?t.context=n:t.pendingContext=n,(t=co(o,l)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),uo(a,t),ms(a,l,o),l}function ec(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tc(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function nc(e,t){tc(e,t),(e=e.alternate)&&tc(e,t)}function rc(e,t,n){var r=null!=n&&null!=n.hydrationOptions&&n.hydrationOptions.mutableSources||null;if(n=new Xs(e,t,null!=n&&!0===n.hydrate),t=Hs(3,null,null,2===t?7:1===t?3:0),n.current=t,t.stateNode=n,lo(t),e[Jr]=n.current,Pr(8===e.nodeType?e.parentNode:e),r)for(e=0;e<r.length;e++){var a=(t=r[e])._getVersion;a=a(t._source),null==n.mutableSourceEagerHydrationData?n.mutableSourceEagerHydrationData=[t,a]:n.mutableSourceEagerHydrationData.push(t,a)}this._internalRoot=n}function ac(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function oc(e,t,n,r,a){var o=n._reactRootContainer;if(o){var i=o._internalRoot;if("function"==typeof a){var l=a;a=function(){var e=ec(i);l.call(e)}}Js(t,i,e,a)}else{if(o=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new rc(e,0,t?{hydrate:!0}:void 0)}(n,r),i=o._internalRoot,"function"==typeof a){var s=a;a=function(){var e=ec(i);s.call(e)}}ks((function(){Js(t,i,e,a)}))}return ec(i)}function ic(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!ac(t))throw Error(i(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:E,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}Wl=function(e,t,n){var r=t.lanes;if(null!==e)if(e.memoizedProps!==t.pendingProps||fa.current)Mi=!0;else{if(0==(n&r)){switch(Mi=!1,t.tag){case 3:Zi(t),Vo();break;case 5:Do(t);break;case 1:ga(t.type)&&wa(t);break;case 4:Oo(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value;var a=t.type._context;ua(Qa,a._currentValue),a._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!=(n&t.child.childLanes)?Xi(e,t,n):(ua(Fo,1&Fo.current),null!==(t=ol(e,t,n))?t.sibling:null);ua(Fo,1&Fo.current);break;case 19:if(r=0!=(n&t.childLanes),0!=(64&e.flags)){if(r)return al(e,t,n);t.flags|=64}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),ua(Fo,Fo.current),r)break;return null;case 23:case 24:return t.lanes=0,Ui(e,t,n)}return ol(e,t,n)}Mi=0!=(16384&e.flags)}else Mi=!1;switch(t.lanes=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=ha(t,pa.current),ao(t,n),a=ii(null,t,r,e,a,n),t.flags|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,ga(r)){var o=!0;wa(t)}else o=!1;t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,lo(t);var l=r.getDerivedStateFromProps;"function"==typeof l&&go(t,r,l,e),a.updater=bo,t.stateNode=a,a._reactInternals=t,ko(t,r,e,n),t=Gi(null,t,r,!0,o,n)}else t.tag=0,Fi(null,t,a,n),t=t.child;return t;case 16:a=t.elementType;e:{switch(null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=(o=a._init)(a._payload),t.type=a,o=t.tag=function(e){if("function"==typeof e)return Gs(e)?1:0;if(null!=e){if((e=e.$$typeof)===L)return 11;if(e===N)return 14}return 2}(a),e=Ya(a,e),o){case 0:t=qi(null,t,a,e,n);break e;case 1:t=Hi(null,t,a,e,n);break e;case 11:t=Bi(null,t,a,e,n);break e;case 14:t=ji(null,t,a,Ya(a.type,e),r,n);break e}throw Error(i(306,a,""))}return t;case 0:return r=t.type,a=t.pendingProps,qi(e,t,r,a=t.elementType===r?a:Ya(r,a),n);case 1:return r=t.type,a=t.pendingProps,Hi(e,t,r,a=t.elementType===r?a:Ya(r,a),n);case 3:if(Zi(t),r=t.updateQueue,null===e||null===r)throw Error(i(282));if(r=t.pendingProps,a=null!==(a=t.memoizedState)?a.element:null,so(e,t),fo(t,r,null,n),(r=t.memoizedState.element)===a)Vo(),t=ol(e,t,n);else{if((o=(a=t.stateNode).hydrate)&&(zo=Vr(t.stateNode.containerInfo.firstChild),jo=t,o=Uo=!0),o){if(null!=(e=a.mutableSourceEagerHydrationData))for(a=0;a<e.length;a+=2)(o=e[a])._workInProgressVersionPrimary=e[a+1],Wo.push(o);for(n=To(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|1024,n=n.sibling}else Fi(e,t,r,n),Vo();t=t.child}return t;case 5:return Do(t),null===e&&Ho(t),r=t.type,a=t.pendingProps,o=null!==e?e.memoizedProps:null,l=a.children,qr(r,a)?l=null:null!==o&&qr(r,o)&&(t.flags|=16),$i(e,t),Fi(e,t,l,n),t.child;case 6:return null===e&&Ho(t),null;case 13:return Xi(e,t,n);case 4:return Oo(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=Co(t,null,r,n):Fi(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Bi(e,t,r,a=t.elementType===r?a:Ya(r,a),n);case 7:return Fi(e,t,t.pendingProps,n),t.child;case 8:case 12:return Fi(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,a=t.pendingProps,l=t.memoizedProps,o=a.value;var s=t.type._context;if(ua(Qa,s._currentValue),s._currentValue=o,null!==l)if(s=l.value,0===(o=cr(s,o)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(s,o):1073741823))){if(l.children===a.children&&!fa.current){t=ol(e,t,n);break e}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var c=s.dependencies;if(null!==c){l=s.child;for(var u=c.firstContext;null!==u;){if(u.context===r&&0!=(u.observedBits&o)){1===s.tag&&((u=co(-1,n&-n)).tag=2,uo(s,u)),s.lanes|=n,null!==(u=s.alternate)&&(u.lanes|=n),ro(s.return,n),c.lanes|=n;break}u=u.next}}else l=10===s.tag&&s.type===t.type?null:s.child;if(null!==l)l.return=s;else for(l=s;null!==l;){if(l===t){l=null;break}if(null!==(s=l.sibling)){s.return=l.return,l=s;break}l=l.return}s=l}Fi(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=(o=t.pendingProps).children,ao(t,n),r=r(a=oo(a,o.unstable_observedBits)),t.flags|=1,Fi(e,t,r,n),t.child;case 14:return o=Ya(a=t.type,t.pendingProps),ji(e,t,a,o=Ya(a.type,o),r,n);case 15:return zi(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:Ya(r,a),null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),t.tag=1,ga(r)?(e=!0,wa(t)):e=!1,ao(t,n),yo(t,r,a),ko(t,r,a,n),Gi(null,t,r,!0,e,n);case 19:return al(e,t,n);case 23:case 24:return Ui(e,t,n)}throw Error(i(156,t.tag))},rc.prototype.render=function(e){Js(e,this._internalRoot,null,null)},rc.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Js(null,e,null,(function(){t[Jr]=null}))},et=function(e){13===e.tag&&(ms(e,4,ps()),nc(e,4))},tt=function(e){13===e.tag&&(ms(e,67108864,ps()),nc(e,67108864))},nt=function(e){if(13===e.tag){var t=ps(),n=fs(e);ms(e,n,t),nc(e,n)}},rt=function(e,t){return t()},Ce=function(e,t,n){switch(t){case"input":if(ne(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=aa(r);if(!a)throw Error(i(90));Q(r),ne(r,a)}}}break;case"textarea":ce(e,n);break;case"select":null!=(t=n.value)&&ie(e,!!n.multiple,t,!1)}},Ne=ws,Oe=function(e,t,n,r,a){var o=Nl;Nl|=4;try{return Ga(98,e.bind(null,t,n,r,a))}finally{0===(Nl=o)&&(Vl(),Va())}},Ie=function(){0==(49&Nl)&&(function(){if(null!==as){var e=as;as=null,e.forEach((function(e){e.expiredLanes|=24&e.pendingLanes,gs(e,$a())}))}Va()}(),Ds())},De=function(e,t){var n=Nl;Nl|=2;try{return e(t)}finally{0===(Nl=n)&&(Vl(),Va())}};var lc={Events:[na,ra,aa,Re,Pe,Ds,{current:!1}]},sc={findFiberByHostInstance:ta,bundleType:0,version:"17.0.2",rendererPackageName:"react-dom"},cc={bundleType:sc.bundleType,version:sc.version,rendererPackageName:sc.rendererPackageName,rendererConfig:sc.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:k.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Xe(e))?null:e.stateNode},findFiberByHostInstance:sc.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var uc=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!uc.isDisabled&&uc.supportsFiber)try{_a=uc.inject(cc),Ea=uc}catch(he){}}t.createPortal=ic,t.hydrate=function(e,t,n){if(!ac(t))throw Error(i(200));return oc(null,e,t,!0,n)}},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var l,s,c,u;if(Array.isArray(e)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(!o(e[s],i[s]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!i.has(s.value[0]))return!1;for(u=e.entries();!(s=u.next()).done;)if(!o(s.value[1],i.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!i.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(e[s]!==i[s])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((l=(c=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(s=l;0!=s--;)if(!Object.prototype.hasOwnProperty.call(i,c[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!=s--;)if(("_owner"!==c[s]&&"__v"!==c[s]&&"__o"!==c[s]||!e.$$typeof)&&!o(e[c[s]],i[c[s]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>G,ql:()=>J});var r=n(7294),a=n(5697),o=n.n(a),i=n(9590),l=n.n(i),s=n(1143),c=n.n(s),u=n(6774),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(a[n]=e[n]);return a}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(g).map((function(e){return g[e]})),k={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},_=Object.keys(k).reduce((function(e,t){return e[k[t]]=t,e}),{}),E=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},S=function(e){var t=E(e,g.TITLE),n=E(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=E(e,"defaultTitle");return t||r||void 0},x=function(e){return E(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},T=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var o=r[a].toLowerCase();if(-1!==e.indexOf(o)&&n[o])return t.concat(n)}return t}),[])},A=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,o=Object.keys(e),i=0;i<o.length;i+=1){var l=o[i],s=l.toLowerCase();-1===t.indexOf(s)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===s&&"stylesheet"===e[s].toLowerCase()||(n=s),-1===t.indexOf(l)||"innerHTML"!==l&&"cssText"!==l&&"itemprop"!==l||(n=l)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][c]&&(a[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var o=Object.keys(a),i=0;i<o.length;i+=1){var l=o[i],s=p({},r[l],a[l]);r[l]=s}return e}),[]).reverse()},L=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},R=function(e){return Array.isArray(e)?e.join(""):e},P=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},N=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},O=[g.NOSCRIPT,g.SCRIPT,g.STYLE],I=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},D=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[k[n]||n]=e[n],t}),t)},F=function(e,t){return t.map((function(t,n){var a,o=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=k[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]})),r.createElement(e,o)}))},B=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,o=M(n,a),[r.createElement(g.TITLE,o,e)];var e,n,a,o},toString:function(){return function(e,t,n,r){var a=D(n),o=R(t);return a?"<"+e+' data-rh="true" '+a+">"+I(o,r)+"</"+e+">":"<"+e+' data-rh="true">'+I(o,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return D(t)}};default:return{toComponent:function(){return F(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+I(r[t],n)+'"';return e?e+" "+a:a}),""),o=r.innerHTML||r.cssText||"",i=-1===O.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(i?"/>":">"+o+"</"+e+">")}),"")}(e,t,n)}}}},j=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,o=e.noscriptTags,i=e.styleTags,l=e.title,s=void 0===l?"":l,c=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=P(e.metaTags,y),o=P(t,b),i=P(n,v);return{priorityMethods:{toComponent:function(){return[].concat(F(g.META,a.priority),F(g.LINK,o.priority),F(g.SCRIPT,i.priority))},toString:function(){return B(g.META,a.priority,r)+" "+B(g.LINK,o.priority,r)+" "+B(g.SCRIPT,i.priority,r)}},metaTags:a.default,linkTags:o.default,scriptTags:i.default}}(e);f=m.priorityMethods,u=m.linkTags,d=m.metaTags,p=m.scriptTags}return{priority:f,base:B(g.BASE,t,r),bodyAttributes:B("bodyAttributes",n,r),htmlAttributes:B("htmlAttributes",a,r),link:B(g.LINK,u,r),meta:B(g.META,d,r),noscript:B(g.NOSCRIPT,o,r),script:B(g.SCRIPT,p,r),style:B(g.STYLE,i,r),title:B(g.TITLE,{title:s,titleAttributes:c},r)}},z=[],U=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?z:n.instances},add:function(e){(n.canUseDOM?z:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?z:n.instances).indexOf(e);(n.canUseDOM?z:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=j({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},$=r.createContext({}),q=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),H="undefined"!=typeof document,G=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new U(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement($.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);G.canUseDOM=H,G.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},G.defaultProps={context:{}},G.displayName="HelmetProvider";var Z=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),a=r.querySelectorAll(e+"[data-rh]"),o=[].slice.call(a),i=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),o.some((function(e,t){return n=t,r.isEqualNode(e)}))?o.splice(n,1):i.push(r)})),o.forEach((function(e){return e.parentNode.removeChild(e)})),i.forEach((function(e){return r.appendChild(e)})),{oldTags:o,newTags:i}},V=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],o=[].concat(a),i=Object.keys(t),l=0;l<i.length;l+=1){var s=i[l],c=t[s]||"";n.getAttribute(s)!==c&&n.setAttribute(s,c),-1===a.indexOf(s)&&a.push(s);var u=o.indexOf(s);-1!==u&&o.splice(u,1)}for(var d=o.length-1;d>=0;d-=1)n.removeAttribute(o[d]);a.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},W=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,o=e.metaTags,i=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,c=e.styleTags,u=e.title,d=e.titleAttributes;V(g.BODY,e.bodyAttributes),V(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=R(e)),V(g.TITLE,t)}(u,d);var p={baseTag:Z(g.BASE,n),linkTags:Z(g.LINK,a),metaTags:Z(g.META,o),noscriptTags:Z(g.NOSCRIPT,i),scriptTags:Z(g.SCRIPT,s),styleTags:Z(g.STYLE,c)},f={},m={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(m[e]=p[e].oldTags)})),t&&t(),l(e,f,m)},K=null,Y=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,o=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:T(["href"],e),bodyAttributes:C("bodyAttributes",e),defer:E(e,"defer"),encode:E(e,"encodeSpecialCharacters"),htmlAttributes:C("htmlAttributes",e),linkTags:A(g.LINK,["rel","href"],e),metaTags:A(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:A(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:x(e),scriptTags:A(g.SCRIPT,["src","innerHTML"],e),styleTags:A(g.STYLE,["cssText"],e),title:S(e),titleAttributes:C("titleAttributes",e),prioritizeSeoTags:L(e,"prioritizeSeoTags")});G.canUseDOM?(t=o,K&&cancelAnimationFrame(K),t.defer?K=requestAnimationFrame((function(){W(t,(function(){K=null}))})):(W(t),K=null)):j&&(a=j(o)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);Y.propTypes={context:q.isRequired},Y.displayName="HelmetDispatcher";var Q=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!l()(N(this.props,"helmetData"),N(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,o=e.newChildProps,i=e.nestedChildren;switch(r.type){case g.TITLE:return p({},a,((t={})[r.type]=i,t.titleAttributes=p({},o),t));case g.BODY:return p({},a,{bodyAttributes:p({},o)});case g.HTML:return p({},a,{htmlAttributes:p({},o)});default:return p({},a,((n={})[r.type]=p({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return c()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,o=r.children,i=h(r,Q),l=Object.keys(i).reduce((function(e,t){return e[_[t]||t]=i[t],e}),{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,o),s){case g.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:o})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,X),a=p({},n),o=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!o||o instanceof U||(o=new U(o.context,o.instances)),o?r.createElement(Y,p({},a,{context:o.value,helmetData:void 0})):r.createElement($.Consumer,null,(function(e){return r.createElement(Y,p({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,o=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function k(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case o:case l:case i:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case g:case h:case s:return e;default:return t}}case a:return t}}}function _(e){return k(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=p,t.Fragment=o,t.Lazy=g,t.Memo=h,t.Portal=a,t.Profiler=l,t.StrictMode=i,t.Suspense=f,t.isAsyncMode=function(e){return _(e)||k(e)===u},t.isConcurrentMode=_,t.isContextConsumer=function(e){return k(e)===c},t.isContextProvider=function(e){return k(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return k(e)===p},t.isFragment=function(e){return k(e)===o},t.isLazy=function(e){return k(e)===g},t.isMemo=function(e){return k(e)===h},t.isPortal=function(e){return k(e)===a},t.isProfiler=function(e){return k(e)===l},t.isStrictMode=function(e){return k(e)===i},t.isSuspense=function(e){return k(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===o||e===d||e===l||e===i||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===h||e.$$typeof===s||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===b)},t.typeOf=k},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}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(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}var l=n(7294),s=n(5697),c=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return l.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=i({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),h=null;function g(){return h||(h=e(m.loader)),h.promise}return c.push(g),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),p=d=function(t){function n(n){var r;return o(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),r._loadModule()})),g(),r.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},r}r(n,t),n.preload=function(){return g()};var i=n.prototype;return i.UNSAFE_componentWillMount=function(){this._loadModule()},i.componentDidMount=function(){this._mounted=!0},i._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},i.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},i._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},i.render=function(){return this.state.loading||this.state.error?l.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(l.Component),o(d,"contextTypes",{loadable:s.shape({report:s.func.isRequired})}),p}function h(e){return m(d,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(p,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return l.Children.only(this.props.children)},t}(l.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}o(g,"propTypes",{report:s.func.isRequired}),o(g,"childContextTypes",{loadable:s.shape({report:s.func.isRequired}).isRequired}),h.Capture=g,h.preloadAll=function(){return new Promise((function(e,t){b(c).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){b(u).then(e,e)}))},e.exports=h},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>l,f:()=>i});var r=n(6550),a=n(7462),o=n(7294);function i(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&i(e.routes,t,n)),a})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?o.createElement(r.rs,n,e.map((function(e,n){return o.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.Z)({},n,{},t,{route:e})):o.createElement(e.component,(0,a.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>y,VK:()=>u,rU:()=>g});var r=n(6550),a=n(5068),o=n(7294),i=n(9318),l=n(7462),s=n(3366),c=n(8776),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.lX)(t.props),t}return(0,a.Z)(t,e),t.prototype.render=function(){return o.createElement(r.F0,{history:this.history,children:this.props.children})},t}(o.Component);o.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,i.ob)(e,null,null,t):e},f=function(e){return e},m=o.forwardRef;void 0===m&&(m=f);var h=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,i=(0,s.Z)(e,["innerRef","navigate","onClick"]),c=i.target,u=(0,l.Z)({},i,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==m&&t||n,o.createElement("a",u)}));var g=m((function(e,t){var n=e.component,a=void 0===n?h:n,u=e.replace,g=e.to,b=e.innerRef,v=(0,s.Z)(e,["component","replace","to","innerRef"]);return o.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=e.history,r=p(d(g,e.location),e.location),s=r?n.createHref(r):"",h=(0,l.Z)({},v,{href:s,navigate:function(){var t=d(g,e.location),r=(0,i.Ep)(e.location)===(0,i.Ep)(p(t));(u||r?n.replace:n.push)(t)}});return f!==m?h.ref=t||b:h.innerRef=b,o.createElement(a,h)}))})),b=function(e){return e},v=o.forwardRef;void 0===v&&(v=b);var y=v((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,i=e.activeClassName,u=void 0===i?"active":i,f=e.activeStyle,m=e.className,h=e.exact,y=e.isActive,w=e.location,k=e.sensitive,_=e.strict,E=e.style,S=e.to,x=e.innerRef,C=(0,s.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return o.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=w||e.location,i=p(d(S,n),n),s=i.pathname,T=s&&s.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),A=T?(0,r.LX)(n.pathname,{path:T,exact:h,sensitive:k,strict:_}):null,L=!!(y?y(A,n):A),R="function"==typeof m?m(L):m,P="function"==typeof E?E(L):E;L&&(R=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(R,u),P=(0,l.Z)({},P,f));var N=(0,l.Z)({"aria-current":L&&a||null,className:R,style:P,to:i},C);return b!==v?N.ref=t||x:N.innerRef=x,o.createElement(g,N)}))}))},6550:(e,t,n)=>{"use strict";n.d(t,{AW:()=>S,F0:()=>y,LX:()=>E,TH:()=>O,k6:()=>N,rs:()=>R,s6:()=>v});var r=n(5068),a=n(7294),o=n(5697),i=n.n(o),l=n(9318),s=n(8776),c=n(7462),u=n(4779),d=n.n(u),p=(n(9864),n(3366)),f=(n(8679),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=a.createContext||function(e,t){var n,o,l="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",s=function(e){function n(){for(var t,n,r,a=arguments.length,o=new Array(a),i=0;i<a;i++)o[i]=arguments[i];return(t=e.call.apply(e,[this].concat(o))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.Z)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((o=r)===(i=a)?0!==o||1/o==1/i:o!=o&&i!=i)?n=0:(n="function"==typeof t?t(r,a):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var o,i},a.render=function(){return this.props.children},n}(a.Component);s.childContextTypes=((n={})[l]=i().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},a.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},a.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},a.getValue=function(){return this.context[l]?this.context[l].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return c.contextTypes=((o={})[l]=i().object,o),{Provider:s,Consumer:c}},g=function(e){var t=h();return t.displayName=e,t},b=g("Router-History"),v=g("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(v.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var w={},k=1e4,_=0;function E(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,o=void 0!==a&&a,i=n.strict,l=void 0!==i&&i,s=n.sensitive,c=void 0!==s&&s;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var a=[],o={regexp:d()(e,a,t),keys:a};return _<k&&(r[e]=o,_++),o}(n,{end:o,strict:l,sensitive:c}),a=r.regexp,i=r.keys,s=a.exec(e);if(!s)return null;var u=s[0],p=s.slice(1),f=e===u;return o&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:i.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var S=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?E(n.pathname,e.props):t.match,o=(0,c.Z)({},t,{location:n,match:r}),i=e.props,l=i.children,u=i.component,d=i.render;return Array.isArray(l)&&function(e){return 0===a.Children.count(e)}(l)&&(l=null),a.createElement(v.Provider,{value:o},o.match?l?"function"==typeof l?l(o):l:u?a.createElement(u,o):d?d(o):null:"function"==typeof l?l(o):null)}))},t}(a.Component);function x(e){return"/"===e.charAt(0)?e:"/"+e}function C(e,t){if(!e)return t;var n=x(e);return 0!==t.pathname.indexOf(n)?t:(0,c.Z)({},t,{pathname:t.pathname.substr(n.length)})}function T(e){return"string"==typeof e?e:(0,l.Ep)(e)}function A(e){return function(){(0,s.Z)(!1)}}function L(){}a.Component;var R=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n,r,o=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var i=e.props.path||e.props.from;r=i?E(o.pathname,(0,c.Z)({},e.props,{path:i})):t.match}})),r?a.cloneElement(n,{location:o,computedMatch:r}):null}))},t}(a.Component);var P=a.useContext;function N(){return P(b)}function O(){return P(v).location}},2408:(e,t,n)=>{"use strict";var r=n(7418),a=60103,o=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var i=60109,l=60110,s=60112;t.Suspense=60113;var c=60115,u=60116;if("function"==typeof Symbol&&Symbol.for){var d=Symbol.for;a=d("react.element"),o=d("react.portal"),t.Fragment=d("react.fragment"),t.StrictMode=d("react.strict_mode"),t.Profiler=d("react.profiler"),i=d("react.provider"),l=d("react.context"),s=d("react.forward_ref"),t.Suspense=d("react.suspense"),c=d("react.memo"),u=d("react.lazy")}var p="function"==typeof Symbol&&Symbol.iterator;function f(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h={};function g(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}function b(){}function v(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(f(85));this.updater.enqueueSetState(this,e,t,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=g.prototype;var y=v.prototype=new b;y.constructor=v,r(y,g.prototype),y.isPureReactComponent=!0;var w={current:null},k=Object.prototype.hasOwnProperty,_={key:!0,ref:!0,__self:!0,__source:!0};function E(e,t,n){var r,o={},i=null,l=null;if(null!=t)for(r in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(i=""+t.key),t)k.call(t,r)&&!_.hasOwnProperty(r)&&(o[r]=t[r]);var s=arguments.length-2;if(1===s)o.children=n;else if(1<s){for(var c=Array(s),u=0;u<s;u++)c[u]=arguments[u+2];o.children=c}if(e&&e.defaultProps)for(r in s=e.defaultProps)void 0===o[r]&&(o[r]=s[r]);return{$$typeof:a,type:e,key:i,ref:l,props:o,_owner:w.current}}function S(e){return"object"==typeof e&&null!==e&&e.$$typeof===a}var x=/\/+/g;function C(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function T(e,t,n,r,i){var l=typeof e;"undefined"!==l&&"boolean"!==l||(e=null);var s=!1;if(null===e)s=!0;else switch(l){case"string":case"number":s=!0;break;case"object":switch(e.$$typeof){case a:case o:s=!0}}if(s)return i=i(s=e),e=""===r?"."+C(s,0):r,Array.isArray(i)?(n="",null!=e&&(n=e.replace(x,"$&/")+"/"),T(i,t,n,"",(function(e){return e}))):null!=i&&(S(i)&&(i=function(e,t){return{$$typeof:a,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(i,n+(!i.key||s&&s.key===i.key?"":(""+i.key).replace(x,"$&/")+"/")+e)),t.push(i)),1;if(s=0,r=""===r?".":r+":",Array.isArray(e))for(var c=0;c<e.length;c++){var u=r+C(l=e[c],c);s+=T(l,t,n,u,i)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=p&&e[p]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),c=0;!(l=e.next()).done;)s+=T(l=l.value,t,n,u=r+C(l,c++),i);else if("object"===l)throw t=""+e,Error(f(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t));return s}function A(e,t,n){if(null==e)return e;var r=[],a=0;return T(e,r,"","",(function(e){return t.call(n,e,a++)})),r}function L(e){if(-1===e._status){var t=e._result;t=t(),e._status=0,e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}if(1===e._status)return e._result;throw e._result}var R={current:null};function P(){var e=R.current;if(null===e)throw Error(f(321));return e}var N={ReactCurrentDispatcher:R,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:w,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:A,forEach:function(e,t,n){A(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return A(e,(function(){t++})),t},toArray:function(e){return A(e,(function(e){return e}))||[]},only:function(e){if(!S(e))throw Error(f(143));return e}},t.Component=g,t.PureComponent=v,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=N,t.cloneElement=function(e,t,n){if(null==e)throw Error(f(267,e));var o=r({},e.props),i=e.key,l=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(l=t.ref,s=w.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(u in t)k.call(t,u)&&!_.hasOwnProperty(u)&&(o[u]=void 0===t[u]&&void 0!==c?c[u]:t[u])}var u=arguments.length-2;if(1===u)o.children=n;else if(1<u){c=Array(u);for(var d=0;d<u;d++)c[d]=arguments[d+2];o.children=c}return{$$typeof:a,type:e.type,key:i,ref:l,props:o,_owner:s}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:l,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:i,_context:e},e.Consumer=e},t.createElement=E,t.createFactory=function(e){var t=E.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:s,render:e}},t.isValidElement=S,t.lazy=function(e){return{$$typeof:u,_payload:{_status:-1,_result:e},_init:L}},t.memo=function(e,t){return{$$typeof:c,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return P().useCallback(e,t)},t.useContext=function(e,t){return P().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return P().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return P().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return P().useLayoutEffect(e,t)},t.useMemo=function(e,t){return P().useMemo(e,t)},t.useReducer=function(e,t,n){return P().useReducer(e,t,n)},t.useRef=function(e){return P().useRef(e)},t.useState=function(e){return P().useState(e)},t.version="17.0.2"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},53:(e,t)=>{"use strict";var n,r,a,o;if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;t.unstable_now=function(){return i.now()}}else{var l=Date,s=l.now();t.unstable_now=function(){return l.now()-s}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var c=null,u=null,d=function(){if(null!==c)try{var e=t.unstable_now();c(!0,e),c=null}catch(n){throw setTimeout(d,0),n}};n=function(e){null!==c?setTimeout(n,0,e):(c=e,setTimeout(d,0))},r=function(e,t){u=setTimeout(e,t)},a=function(){clearTimeout(u)},t.unstable_shouldYield=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var p=window.setTimeout,f=window.clearTimeout;if("undefined"!=typeof console){var m=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof m&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var h=!1,g=null,b=-1,v=5,y=0;t.unstable_shouldYield=function(){return t.unstable_now()>=y},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):v=0<e?Math.floor(1e3/e):5};var w=new MessageChannel,k=w.port2;w.port1.onmessage=function(){if(null!==g){var e=t.unstable_now();y=e+v;try{g(!0,e)?k.postMessage(null):(h=!1,g=null)}catch(n){throw k.postMessage(null),n}}else h=!1},n=function(e){g=e,h||(h=!0,k.postMessage(null))},r=function(e,n){b=p((function(){e(t.unstable_now())}),n)},a=function(){f(b),b=-1}}function _(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,a=e[r];if(!(void 0!==a&&0<x(a,t)))break e;e[r]=t,e[n]=a,n=r}}function E(e){return void 0===(e=e[0])?null:e}function S(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length;r<a;){var o=2*(r+1)-1,i=e[o],l=o+1,s=e[l];if(void 0!==i&&0>x(i,n))void 0!==s&&0>x(s,i)?(e[r]=s,e[l]=n,r=l):(e[r]=i,e[o]=n,r=o);else{if(!(void 0!==s&&0>x(s,n)))break e;e[r]=s,e[l]=n,r=l}}}return t}return null}function x(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var C=[],T=[],A=1,L=null,R=3,P=!1,N=!1,O=!1;function I(e){for(var t=E(T);null!==t;){if(null===t.callback)S(T);else{if(!(t.startTime<=e))break;S(T),t.sortIndex=t.expirationTime,_(C,t)}t=E(T)}}function D(e){if(O=!1,I(e),!N)if(null!==E(C))N=!0,n(M);else{var t=E(T);null!==t&&r(D,t.startTime-e)}}function M(e,n){N=!1,O&&(O=!1,a()),P=!0;var o=R;try{for(I(n),L=E(C);null!==L&&(!(L.expirationTime>n)||e&&!t.unstable_shouldYield());){var i=L.callback;if("function"==typeof i){L.callback=null,R=L.priorityLevel;var l=i(L.expirationTime<=n);n=t.unstable_now(),"function"==typeof l?L.callback=l:L===E(C)&&S(C),I(n)}else S(C);L=E(C)}if(null!==L)var s=!0;else{var c=E(T);null!==c&&r(D,c.startTime-n),s=!1}return s}finally{L=null,R=o,P=!1}}var F=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){N||P||(N=!0,n(M))},t.unstable_getCurrentPriorityLevel=function(){return R},t.unstable_getFirstCallbackNode=function(){return E(C)},t.unstable_next=function(e){switch(R){case 1:case 2:case 3:var t=3;break;default:t=R}var n=R;R=t;try{return e()}finally{R=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=F,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=R;R=e;try{return t()}finally{R=n}},t.unstable_scheduleCallback=function(e,o,i){var l=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0<i?l+i:l:i=l,e){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return e={id:A++,callback:o,priorityLevel:e,startTime:i,expirationTime:s=i+s,sortIndex:-1},i>l?(e.sortIndex=i,_(T,e),null===E(C)&&e===E(T)&&(O?a():O=!0,r(D,i-l))):(e.sortIndex=s,_(C,e),N||P||(N=!0,n(M))),e},t.unstable_wrapCallback=function(e){var t=R;return function(){var n=R;R=t;try{return e.apply(this,arguments)}finally{R=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var o=Object.keys(e),i=Object.keys(t);if(o.length!==i.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),s=0;s<o.length;s++){var c=o[s];if(!l(c))return!1;var u=e[c],d=t[c];if(!1===(a=n?n.call(r,u,d,c):void 0)||void 0===a&&u!==d)return!1}return!0}},3250:(e,t,n)=>{"use strict";var r=n(7294);var a="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},o=r.useState,i=r.useEffect,l=r.useLayoutEffect,s=r.useDebugValue;function c(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!a(e,n)}catch(r){return!0}}var u="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=o({inst:{value:n,getSnapshot:t}}),a=r[0].inst,u=r[1];return l((function(){a.value=n,a.getSnapshot=t,c(a)&&u({inst:a})}),[e,n,t]),i((function(){return c(a)&&u({inst:a}),e((function(){c(a)&&u({inst:a})}))}),[e]),s(n),n};t.useSyncExternalStore=void 0!==r.useSyncExternalStore?r.useSyncExternalStore:u},1688:(e,t,n)=>{"use strict";e.exports=n(3250)},6809:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={title:"etherealengine",tagline:"An open source solution for hosting, creating and developing immersive social spaces, built on top of WebXR, React & Feathers.",url:"https://etherealengine.github.io",baseUrl:"/etherealengine-docs/",onBrokenLinks:"warn",onBrokenMarkdownLinks:"warn",favicon:"img/favicon.ico",organizationName:"etherealengine",projectName:"etherealengine-docs",i18n:{defaultLocale:"en",locales:["en","es"],path:"i18n",localeConfigs:{}},plugins:[],presets:[["classic",{docs:{sidebarPath:"/home/runner/work/etherealengine/etherealengine/docs/sidebars.js",exclude:["**/_*.{js,jsx,ts,tsx,md,mdx}"],editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/"},theme:{customCss:"/home/runner/work/etherealengine/etherealengine/docs/src/css/custom.css"}}]],themeConfig:{algolia:{appId:"N5OIDFHT9B",apiKey:"06604779928fc73656c9ae03fae1f0b1",indexName:"etherealengine",contextualSearch:!0,searchParameters:{},searchPagePath:"search"},navbar:{title:"Ethereal Engine",logo:{alt:"Ethereal Engine Logo",src:"img/logo.svg"},items:[{to:"docs/",activeBasePath:"docs",label:"Docs",position:"left"},{href:"https://etherealengine.org/",label:"Ethereal Engine",position:"right"},{type:"localeDropdown",position:"right",dropdownItemsBefore:[],dropdownItemsAfter:[]}],hideOnScroll:!1},footer:{style:"dark",links:[{title:"Social",items:[{label:"Twitter",href:"https://twitter.com/xr_engine"},{label:"Facebook",href:"https://www.facebook.com/xrengine/"},{label:"Discord",href:"https://discord.gg/xrf"}]},{title:"Resources",items:[{label:"Github",href:"https://github.com/etherealengine/etherealengine"},{label:"Npm",href:"https://www.npmjs.com/search?q=%40etherealengine"}]},{title:"More",items:[{label:"Ethereal Engine",href:"https://www.etherealengine.org/"},{label:"Open Collective",href:"https://opencollective.com/etherealengine"}]}],copyright:"Copyright \xa9 2023 Ethereal Engine."},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:[],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},colorMode:{defaultMode:"light",disableSwitch:!1,respectPrefersColorScheme:!1},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},baseUrlIssueBanner:!0,onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>a})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}n.d(t,{Z:()=>r})},8776:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=!0,a="Invariant failed";function o(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,o=n?"".concat(a,": ").concat(n):a;throw new Error(o)}}},7529:e=>{"use strict";e.exports={}},6887:e=>{"use strict";e.exports=JSON.parse('{"/etherealengine-docs/markdown-page-d17":{"__comp":"1f391b9e","__context":{"plugin":"cf339e2e"},"content":"393be207"},"/etherealengine-docs/search-fe4":{"__comp":"1a4e3797","__context":{"plugin":"33e7527e"}},"/etherealengine-docs/docs-376":{"__comp":"1be78505","__context":{"plugin":"222ee964"},"versionMetadata":"935f2afb"},"/etherealengine-docs/docs/-84b":{"__comp":"17896441","content":"fc66d9af"},"/etherealengine-docs/docs/creator/-c0c":{"__comp":"17896441","content":"c538f40f"},"/etherealengine-docs/docs/creator/avatars/-e46":{"__comp":"17896441","content":"6807199d"},"/etherealengine-docs/docs/creator/concepts/-261":{"__comp":"17896441","content":"0991b023"},"/etherealengine-docs/docs/creator/concepts/editor_scenes_locations-687":{"__comp":"17896441","content":"b04e8f41"},"/etherealengine-docs/docs/creator/development/-a0f":{"__comp":"17896441","content":"4a62c6ed"},"/etherealengine-docs/docs/creator/development/actions_event_sourcing-07b":{"__comp":"17896441","content":"d05402c5"},"/etherealengine-docs/docs/creator/development/behave_graph-f1b":{"__comp":"17896441","content":"d519f5a1"},"/etherealengine-docs/docs/creator/development/ecs-2d7":{"__comp":"17896441","content":"d43455fa"},"/etherealengine-docs/docs/creator/development/networking-d32":{"__comp":"17896441","content":"0304d7f4"},"/etherealengine-docs/docs/creator/development/projects_overview-ebc":{"__comp":"17896441","content":"4a109b8c"},"/etherealengine-docs/docs/creator/development/state_management-e64":{"__comp":"17896441","content":"14d2cd64"},"/etherealengine-docs/docs/creator/importing_assets/-7b2":{"__comp":"17896441","content":"8df89772"},"/etherealengine-docs/docs/creator/studio/-796":{"__comp":"17896441","content":"28d03809"},"/etherealengine-docs/docs/creator/testing/-cf6":{"__comp":"17896441","content":"47408852"},"/etherealengine-docs/docs/creator/testing/debugging-b7c":{"__comp":"17896441","content":"75750052"},"/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceservers-c39":{"__comp":"17896441","content":"d50cf8bd"},"/etherealengine-docs/docs/creator/testing/debugging_device_wsl-829":{"__comp":"17896441","content":"271238cb"},"/etherealengine-docs/docs/creator/testing/reasonable_code-360":{"__comp":"17896441","content":"54e37525"},"/etherealengine-docs/docs/creator/testing/test_driven_development-0d2":{"__comp":"17896441","content":"cc938c89"},"/etherealengine-docs/docs/creator/testing/testing_intro-efe":{"__comp":"17896441","content":"a47a1e93"},"/etherealengine-docs/docs/creator/tutorials/-b8d":{"__comp":"17896441","content":"917fb754"},"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/-1dd":{"__comp":"17896441","content":"4c80fdcb"},"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridge-a34":{"__comp":"17896441","content":"530a89a7"},"/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridge-cd2":{"__comp":"17896441","content":"82399a21"},"/etherealengine-docs/docs/guest/-f3a":{"__comp":"17896441","content":"a1c60d7a"},"/etherealengine-docs/docs/host/-3a2":{"__comp":"17896441","content":"bddbf10d"},"/etherealengine-docs/docs/host/Admin_Dashboard/-258":{"__comp":"17896441","content":"0f5dde8f"},"/etherealengine-docs/docs/host/devops_deployment/-30b":{"__comp":"17896441","content":"b68e3f8b"},"/etherealengine-docs/docs/host/devops_deployment/AWS_setup-3ef":{"__comp":"17896441","content":"58222842"},"/etherealengine-docs/docs/host/devops_deployment/database_migrations-7e5":{"__comp":"17896441","content":"9a2a3fee"},"/etherealengine-docs/docs/host/devops_deployment/docker_desktop-8e1":{"__comp":"17896441","content":"a91c512d"},"/etherealengine-docs/docs/host/devops_deployment/installing_projects-f48":{"__comp":"17896441","content":"0346e14a"},"/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetes-226":{"__comp":"17896441","content":"d88112b6"},"/etherealengine-docs/docs/host/devops_deployment/microk8s_linux-6ab":{"__comp":"17896441","content":"c7af7f81"},"/etherealengine-docs/docs/host/devops_deployment/microk8s_windows-7ec":{"__comp":"17896441","content":"3c3cda30"},"/etherealengine-docs/docs/host/devops_deployment/minikube-ac8":{"__comp":"17896441","content":"ea08158a"},"/etherealengine-docs/docs/host/devops_deployment/release_helm_chart-e29":{"__comp":"17896441","content":"24869598"},"/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projects-d72":{"__comp":"17896441","content":"12905b1d"},"/etherealengine-docs/docs/host/devops_deployment/tutorials/-8ef":{"__comp":"17896441","content":"95bfc3a6"},"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/-997":{"__comp":"17896441","content":"291a898d"},"/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started-ab4":{"__comp":"17896441","content":"4b422948"},"/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deployment-169":{"__comp":"17896441","content":"dcc1f912"},"/etherealengine-docs/docs/host/installation/-0f0":{"__comp":"17896441","content":"f7429bc1"},"/etherealengine-docs/docs/host/installation/advanced_setup-81c":{"__comp":"17896441","content":"d7cf77e2"},"/etherealengine-docs/docs/host/installation/basic_setup-eea":{"__comp":"17896441","content":"ebc45004"},"/etherealengine-docs/docs/host/installation/docker-706":{"__comp":"17896441","content":"e988a1b0"},"/etherealengine-docs/docs/host/installation/install_troubleshooting-105":{"__comp":"17896441","content":"46dcad74"},"/etherealengine-docs/docs/host/installation/mac_os_x-1bf":{"__comp":"17896441","content":"86c50ec3"},"/etherealengine-docs/docs/host/installation/opensearch-589":{"__comp":"17896441","content":"06bf4b13"},"/etherealengine-docs/docs/host/installation/running_on_static_IP-04e":{"__comp":"17896441","content":"3ec03ade"},"/etherealengine-docs/docs/host/installation/windows-cc4":{"__comp":"17896441","content":"b5eb9e9a"},"/etherealengine-docs/docs/host/installation/windows_wsl-47d":{"__comp":"17896441","content":"15dae980"},"/etherealengine-docs/-21d":{"__comp":"1df93b7f","__context":{"plugin":"cf339e2e"},"config":"5e9f5e1a"}}')}},e=>{e.O(0,[3312],(()=>{return t=9383,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/main.a156226e.js.LICENSE.txt b/assets/js/main.a156226e.js.LICENSE.txt new file mode 100644 index 000000000000..eb75d69107c8 --- /dev/null +++ b/assets/js/main.a156226e.js.LICENSE.txt @@ -0,0 +1,63 @@ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/** + * @license React + * use-sync-external-store-shim.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + */ + +/** @license React v0.20.2 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/assets/js/runtime~main.6c67445e.js b/assets/js/runtime~main.6c67445e.js new file mode 100644 index 000000000000..8f226a0910ef --- /dev/null +++ b/assets/js/runtime~main.6c67445e.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,d,f,c,t={},r={};function b(e){var a=r[e];if(void 0!==a)return a.exports;var d=r[e]={id:e,loaded:!1,exports:{}};return t[e].call(d.exports,d,d.exports,b),d.loaded=!0,d.exports}b.m=t,b.c=r,e=[],b.O=(a,d,f,c)=>{if(!d){var t=1/0;for(i=0;i<e.length;i++){d=e[i][0],f=e[i][1],c=e[i][2];for(var r=!0,o=0;o<d.length;o++)(!1&c||t>=c)&&Object.keys(b.O).every((e=>b.O[e](d[o])))?d.splice(o--,1):(r=!1,c<t&&(t=c));if(r){e.splice(i--,1);var n=f();void 0!==n&&(a=n)}}return a}c=c||0;for(var i=e.length;i>0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[d,f,c]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var c=Object.create(null);b.r(c);var t={};a=a||[null,d({}),d([]),d(d)];for(var r=2&f&&e;"object"==typeof r&&!~a.indexOf(r);r=d(r))Object.getOwnPropertyNames(r).forEach((a=>t[a]=()=>e[a]));return t.default=()=>e,b.d(c,t),c},b.d=(e,a)=>{for(var d in a)b.o(a,d)&&!b.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:a[d]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,d)=>(b.f[d](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",176:"d88112b6",301:"6807199d",314:"d7cf77e2",401:"222ee964",532:"75750052",543:"b68e3f8b",720:"0346e14a",943:"4a109b8c",1205:"d43455fa",1364:"d50cf8bd",1423:"28d03809",1473:"82399a21",1489:"15dae980",2130:"47408852",2142:"b04e8f41",2345:"12905b1d",2606:"291a898d",2901:"14d2cd64",2984:"33e7527e",3085:"1f391b9e",3113:"fc66d9af",3179:"f7429bc1",3237:"1df93b7f",3573:"24869598",3666:"dcc1f912",3709:"cc938c89",3850:"c538f40f",3881:"4b422948",3976:"0f5dde8f",4380:"c7af7f81",4438:"cf339e2e",4449:"a91c512d",4705:"e988a1b0",4995:"ea08158a",5003:"271238cb",5046:"d519f5a1",5111:"530a89a7",5194:"ebc45004",5229:"9a2a3fee",5459:"95bfc3a6",5520:"46dcad74",5572:"06bf4b13",5624:"4a62c6ed",5992:"a47a1e93",6524:"0991b023",6658:"b5eb9e9a",6718:"54e37525",6916:"3ec03ade",6970:"d05402c5",7053:"917fb754",7414:"393be207",7918:"17896441",7920:"1a4e3797",8511:"4c80fdcb",8620:"8df89772",8625:"86c50ec3",8718:"58222842",8823:"bddbf10d",8949:"a1c60d7a",8953:"0304d7f4",9037:"3c3cda30",9514:"1be78505"}[e]||e)+"."+{53:"f14aaa66",176:"b234a8cf",272:"9b1a0f8c",301:"e53be443",314:"9e856bfc",401:"1c0e3f8c",532:"ed83fca3",543:"506d688c",720:"b3b01a5c",943:"cb0176b6",1205:"4acf96f4",1364:"84d91e0f",1423:"10ee48b7",1426:"3913c64b",1473:"a358d094",1489:"a0d880ae",2130:"86d4c0f1",2142:"076998ce",2345:"3d4cf35d",2606:"adadca59",2901:"abc81f39",2984:"bca6e6d3",3085:"75a9ca1a",3113:"b31bd970",3179:"99a5afc2",3237:"7f8f9032",3573:"a0fec5ff",3666:"77ac3288",3709:"e1255a30",3850:"489bcf12",3881:"50ee1827",3976:"fe7a1c7a",4380:"8ce45faa",4438:"43e40fa8",4449:"b90fd2d8",4705:"01f59a3e",4972:"512e2090",4995:"89b4f73b",5003:"1d53c9db",5046:"4eec9ca7",5111:"f88b4cdd",5194:"00601ac1",5229:"080e864f",5459:"52bf81df",5520:"49e01d47",5572:"0975895e",5624:"61dce0d2",5992:"04128bc8",6524:"bcdd8fa9",6658:"4e889fbb",6718:"176276c0",6916:"21fb0b42",6945:"326f966e",6970:"9693efa0",7053:"1cd49318",7414:"7aa10cb1",7918:"07f91ca7",7920:"dd8146f2",8511:"d2ab6915",8620:"0da26743",8625:"37681b55",8718:"91787d57",8823:"1a3063ba",8894:"2c471ab3",8949:"aa5dd692",8953:"46f13c57",9037:"cb790227",9514:"dc6e92dc"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},c="@etherealengine/docs:",b.l=(e,a,d,t)=>{if(f[e])f[e].push(a);else{var r,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var l=n[i];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==c+d){r=l;break}}r||(o=!0,(r=document.createElement("script")).charset="utf-8",r.timeout=120,b.nc&&r.setAttribute("nonce",b.nc),r.setAttribute("data-webpack",c+d),r.src=e),f[e]=[a];var u=(a,d)=>{r.onerror=r.onload=null,clearTimeout(s);var c=f[e];if(delete f[e],r.parentNode&&r.parentNode.removeChild(r),c&&c.forEach((e=>e(d))),a)return a(d)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=u.bind(null,r.onerror),r.onload=u.bind(null,r.onload),o&&document.head.appendChild(r)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/etherealengine-docs/",b.gca=function(e){return e={17896441:"7918",24869598:"3573",47408852:"2130",58222842:"8718",75750052:"532","935f2afb":"53",d88112b6:"176","6807199d":"301",d7cf77e2:"314","222ee964":"401",b68e3f8b:"543","0346e14a":"720","4a109b8c":"943",d43455fa:"1205",d50cf8bd:"1364","28d03809":"1423","82399a21":"1473","15dae980":"1489",b04e8f41:"2142","12905b1d":"2345","291a898d":"2606","14d2cd64":"2901","33e7527e":"2984","1f391b9e":"3085",fc66d9af:"3113",f7429bc1:"3179","1df93b7f":"3237",dcc1f912:"3666",cc938c89:"3709",c538f40f:"3850","4b422948":"3881","0f5dde8f":"3976",c7af7f81:"4380",cf339e2e:"4438",a91c512d:"4449",e988a1b0:"4705",ea08158a:"4995","271238cb":"5003",d519f5a1:"5046","530a89a7":"5111",ebc45004:"5194","9a2a3fee":"5229","95bfc3a6":"5459","46dcad74":"5520","06bf4b13":"5572","4a62c6ed":"5624",a47a1e93:"5992","0991b023":"6524",b5eb9e9a:"6658","54e37525":"6718","3ec03ade":"6916",d05402c5:"6970","917fb754":"7053","393be207":"7414","1a4e3797":"7920","4c80fdcb":"8511","8df89772":"8620","86c50ec3":"8625",bddbf10d:"8823",a1c60d7a:"8949","0304d7f4":"8953","3c3cda30":"9037","1be78505":"9514"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,3312:0};b.f.j=(a,d)=>{var f=b.o(e,a)?e[a]:void 0;if(0!==f)if(f)d.push(f[2]);else if(/^(1303|3312)$/.test(a))e[a]=0;else{var c=new Promise(((d,c)=>f=e[a]=[d,c]));d.push(f[2]=c);var t=b.p+b.u(a),r=new Error;b.l(t,(d=>{if(b.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var c=d&&("load"===d.type?"missing":d.type),t=d&&d.target&&d.target.src;r.message="Loading chunk "+a+" failed.\n("+c+": "+t+")",r.name="ChunkLoadError",r.type=c,r.request=t,f[1](r)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,d)=>{var f,c,t=d[0],r=d[1],o=d[2],n=0;if(t.some((a=>0!==e[a]))){for(f in r)b.o(r,f)&&(b.m[f]=r[f]);if(o)var i=o(b)}for(a&&a(d);n<t.length;n++)c=t[n],b.o(e,c)&&e[c]&&e[c][0](),e[c]=0;return b.O(i)},d=self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[];d.forEach(a.bind(null,0)),d.push=a.bind(null,d.push.bind(d))})()})(); \ No newline at end of file diff --git a/docs/creator/avatars/index.html b/docs/creator/avatars/index.html new file mode 100644 index 000000000000..f7894844ee32 --- /dev/null +++ b/docs/creator/avatars/index.html @@ -0,0 +1,16 @@ +<!doctype html> +<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-creator/avatars/readme"> +<head> +<meta charset="UTF-8"> +<meta name="generator" content="Docusaurus v2.4.0"> +<title data-rh="true">readme | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/creator/concepts/editor_scenes_locations/index.html b/docs/creator/concepts/editor_scenes_locations/index.html new file mode 100644 index 000000000000..cf546d386ef9 --- /dev/null +++ b/docs/creator/concepts/editor_scenes_locations/index.html @@ -0,0 +1,16 @@ + + + + + +Studio & Locations | etherealengine + + + + +
+

Studio & Locations

Scene Studio

Navigating to /studio will show you the projects page, where you can open existing projects or create a new one.

Opening a project will route you to /studio/<projectName> where the project studio will load. From here, you can open a scene, which will route you again to /studio/<projectName>/<sceneName>

The scene consists of a list of 'nodes' which act as templates / prefabs. These are what you would normally expect in a scene studio, such as models, colliders and audio, but we also support a wide range of integrations, such as shopify, wordpress and even portals to let you traverse between worlds.

To save a scene with Ctrl+S or in the top left Hamburger menu.

Locations & Instances

Locations can be thought of as instantiations of scene. This is how you connect your scene to a shared session.

Locations can be loaded via the /location/<locationName> route, where locationName is the name of the location. By default, the locations default, apartment and sky-station are added.

An instance is an individual session running at a location, in which users are connected together in real time. This allows the deployment to scale events and locations to potentially millions of concurrent users without having to support them all on a single instance.

There are two types of instances: world instances and media instances. World instances handle the spatial objects in the scene, such as avatars, vehicles and grabbables. Media instances handle realtime audio, video and screenshare.

Media instances can be tied to a location, or exist ephemerally as a group call, called parties.

Instances can also be customised with the 'matchmaker' functionality to create private rooms.

Adding a new location is done from /admin/locations route, and live instances can be viewed from /admin/instances.

+ + + + \ No newline at end of file diff --git a/docs/creator/concepts/index.html b/docs/creator/concepts/index.html new file mode 100644 index 000000000000..5d5ad3bf57ce --- /dev/null +++ b/docs/creator/concepts/index.html @@ -0,0 +1,16 @@ + + + + + +Concepts | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/creator/development/actions_event_sourcing/index.html b/docs/creator/development/actions_event_sourcing/index.html new file mode 100644 index 000000000000..6973818097f7 --- /dev/null +++ b/docs/creator/development/actions_event_sourcing/index.html @@ -0,0 +1,16 @@ + + + + + +Event Sourcing | etherealengine + + + + +
+

Event Sourcing

Actions

Actions are a way to control state changes in your application. Once defined, they can be dispatched, which will then populate the outgoing queue to be processed on the next frame.

All actions are dispatched to a topic, by default this is the default topic. Topics are used to specify that actions are to be routed to specific networks.

When an action is dispatched, it is added to the incoming action queue. If it's topic is networked, it is also added to the outgoing queue for it's topic.

At the end of the animation frame, any actions in a network topic's outgoing queue are sent to that topic's network.

If the peer is the host of a networked action's topic, the action is sent to all other peers, otherwise it is just sent to the host. This can be opted out of by specifying the $to property on an action, which informs the host to forward the action only to that user's.

At the start of the next animation frame, action queues are populated with incoming actions. These actions are then processed in the order they were received, by systems in the order the systems are registered.

+ + + + \ No newline at end of file diff --git a/docs/creator/development/behave_graph/index.html b/docs/creator/development/behave_graph/index.html new file mode 100644 index 000000000000..2ec43b8330fa --- /dev/null +++ b/docs/creator/development/behave_graph/index.html @@ -0,0 +1,30 @@ + + + + + +Introduction | etherealengine + + + + +
+

Introduction

  • Overview
  • Audience

Getting Started

  • Installation
  • Configuration

Code Overview:

  • High-Level Architecture
  • Key Concepts
  • Engine Nodes

Usage

  • Examples

Configuration and Customization

  • Making new nodes

1. Introduction

1.1 Overview

Behavior graphs are expressive, deterministic, and extensible state machines that can encode arbitrarily complex behavior.

Behavior graphs are a popular choice for implementing visual scripting languages. Prominent game engines like Unreal Engine and Unity have adopted behavior graphs as an essential component of their visual scripting systems. For example, Unreal Engine's Blueprints, Unity's Visual Scripting, and NVIDIA Omniverse's OmniGraph rely on behavior graphs to enable game designers and developers to create complex behaviors without writing code directly.

Within the Ethereal Engine, the Behavior Graphs feature plays a pivotal role by providing a no-code interface to the engine and by interacting with the engine while modeling, organizing, controlling and assigning complex behaviors on entities, with ease.

1.2 Audience

Behavior Graphs in the Ethereal engine target developers, designers, artists, and non-technical users. This visual scripting feature enables easy implementation of complex logic and actions for entities without the need for writing scripts. It fosters collaboration and empowers diverse individuals to create immersive experiences and interactive content within the engine.

2. Getting Started

2.1 Installation - at the moment the behavior graph implementation is available on the behave-graph-integration branch in the Ethereal Engine Repository

Clone the branch and follow general Ethereal engine installation steps +general instructions

The Behavior Graphs must be defined in the studio and thus require a user to have admin privileges

2.2 Configuration

The Behave graph is implemented as a component in the engine following the ECS(Entity component system) architecture in the engine.

Users can add and remove a behave graph component from an entity

Step 1: find the behave graph component under the scripting section in the component shelf in the right side of the screen +Step 2:

  1. double click on the component tor drag and drop into scene to add a new entity with the behave graph component into the screen
  2. Drag and drop into the hierarchy panel on another entity to add to scene as child of the selected entity
  3. Drag and drop into properties panel of selected entity to add component to entity

The behave graph properties panel has two properties:

  • Run graph: runs the graph in headless mode as part of the engine
  • Disable graph: disable graph from playing

2.3 Creating your First graph

Before we dive into creating the graph let's take a look at the graph panel

The graph panel consists of the the panel itself, panel buttons, nodes and connections

The default behave graph consists of an

On start event node

On tick event node

Logger node

To navigate across the panel, drag across the surface of the panel

2.3.1 buttons in the graph panel

The buttons panel is location in the bottom left side of the screen

The buttons are as follows

Zoom in: zoom into the graph viewport

Zoom out: zoom out of the graph viewport

Fit view: tries to fit all nodes into the screen at the same time, if not possible it centers the view at the center of all nodes

Lock graph: Toggles ability to graph edit

Help: Opens an instruction modal for making graphs

Load Graph: Opens a modal, user can paste graph json in the input field to load the corresponding graph

Save Graph: Opens a model, user can copy the graph json from the text box and save as needed

Play Graph: runs headful version of the graph connected to the graph editor

2.3.2 Saving Graph

The graph has its own json which is also part of the scene json, therefore the user needs to save the graph in as its own json which then must be saved as a part of the scene

The graph json is autosaved every 5 seconds the graph panel i open and whenever the graph panel is closed (the component unmounts)

The graph and overall changes to the scene must be saved using the save scene option from the main menu

2.3.3 Playing a graph

A graph can be played in two modes, headful and headless,

headful mode play - headful mode, activated by pressing the play button in the graph buttons, graph stops executing when the panel is closed or component unmounts, meant for quick testing, setting scene variables and rapid development

Headless mode play - headless mode, play activated from properties panel, execution does not stop unless play is toggled off again from the properties panel

To play all graphs in the scene the user can use the play scene button from the top toolbar

NOTE: headful and headless plays must be managed separately

Ok finally with all this context, lets add a node

To add a node, right click anywhere on the graph panel

This will open up the node picker select window,

Type in the search input to filter nodes by prefix +Click on the node to add to the panel

Lets add a logger node and connect it to the on tick event

To connect the flow of the nodes , drag from one flow socket to another +There can be only one flow output from one flow output socket

But there can be multiple inputs to a flow input socket

To play the graph click on the play graph button

Well done, outputs to the log can be seen in the dev tools console

TODO: add pictures

  1. Code Overview:

Node Types

  • Events You can implement arbitrary events that start execution: Start, Tick
  • Actions You can implement actions that trigger animations, scene scene variations, or update internal state: Log, Play Gltf animation, Play Audio, Play Video, etc
  • Logic You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes.
  • Queries You can query the state from the system.
  • Flow Control Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop
  • Variables You can create, set and get variable values.
  • Custom Events You can create, listen to and trigger custom events.

3.2 Key Concepts

Nodes - +Connections - +Flow -

Events

Set and Get Scene Properties

Registering nodes

Value Types

Value type Converters

3.3 Engine Nodes

3.3.1 Entity

Teleport Entity +Add Entity +Delete Entity +Get Entity from Scene +Get Camera Entity

3.3.2 Component

Add Component

Delete Component

Get component from registry +Get component from entity

3.3.3 Engine

Play Video

Play Audio

Play Gltf Animations

Get Avatar animations

Fade Camera

Switch Scene

3.3.4 Events

Either in pairs of trigger and listener , or just listener +On Button State

triggerLoadAsset -> onLoadAsset

4. Usage

Add some example screenshots and explain

5.Configuration and Customization

5.1 Making new nodes

Describe the creation of nodes

Making flow nodes +Making Event node +Making Value types

Making Function node

Extending Dependencies

+ + + + \ No newline at end of file diff --git a/docs/creator/development/ecs/index.html b/docs/creator/development/ecs/index.html new file mode 100644 index 000000000000..2a4333a4f7ed --- /dev/null +++ b/docs/creator/development/ecs/index.html @@ -0,0 +1,16 @@ + + + + + +Entities, Components and Systems | etherealengine + + + + +
+

Entities, Components and Systems

What is an ECS?

ECS refers to the "Entity Component System" architecture paradigm. In this pattern, data is organised into abstract objects called components that allows for composition instead of inheritance. An entity is simply collection of components identified by a number. Systems are functions that operate on these entities and components.

Component Definitions

Components support two types of data: Structure of Arrays and Array of Structures.

Structure of Arrays Component Data

Structure of Arrays is a data layout that stores data in a way that is more cache friendly. It is a good choice for data that is accessed often and in a predictable way, such as transform data.

const TransformComponent = defineComponent({
name: 'TransformComponent',
schema: {
position: Types.f64,
rotation: Types.f64,
scale: Types.f64
}
})

Reactive Component Data

Array of Structures is an implementation unique to Ethereal Engine, using React and Hookstate under the hood, it allows for reactive data binding. This means that when a property is changed, all effects depending on it will be triggered. It is a good choice for data that is accessed infrequently and in an unpredictable way, especially when react style logic is associated with it.

const DebugArrowComponent = defineComponent({
name: 'DebugArrowComponent',

onInit: (entity) => {
return {
color: 0xffffff,
direction: new Vector3(),
position: new Vector3()
}
},

onSet: (entity, component, json) => {
if (!json) return

if (json.color) component.color.set(json.color)
if (json.direction) component.direction.set(json.direction)
if (json.position) component.position.set(json.position)
}
})

onInit

(entity: Entity) => ComponentType<C>

onInit is a function that is called when setComponent is called on an entity that does not have the component in question. It is passed the entity number and should return an object with the initial values for the component.

onSet

entity: Entity, component: ComponentType<C>, json: SerializedComponentType<C>) => void

onSet is a function that is called each time setComponent is called. It is passed the entity number, the component object and json object. This is how reactive data can be updated in batch, allowing for tighter data flow, such as deserializing scene data.

onRemove

(entity: Entity, component: ComponentType<C>) => void

onRemove is a function that is called when removeComponent is called on an entity that has the component in question. It is passed the entity number and the component object. This is where you would clean up any resources associated with the component.

toJSON

(entity: Entity, component: ComponentType<C>) => SerializedComponentType<C>

toJSON is a function that is called when serializeComponent is called on an entity that has the component in question. It is passed the entity number and the component object. This is where serialized data can be generated, such as for saving a scene.

jsonID

string

jsonID is a string that is used to identify the component in json. It is used when deserializing and serializing scenes.

reactor

function(props: { root: EntityRoot }) => void

reactor specifies a function that exists for the duration of this component instance. This is where you would add any effects that depend on the component.

Update Loop

The engine uses a very similar model to Unity's update loop (found here https://docs.unity3d.com/Manual/ExecutionOrder.html). It has a frame update, called once per frame, of which inside is a fixed update, which operates on an accumulator system. This system ensures a stable number of updates per second independent of the framerate. This means it may have 0 to many updates in a given frame.

Ethereal Engine implements this with pipelines, which are collections of systems to execute in order.

Queries

Queries are used to select entities that have a set of components. They are used to define the entities that a system will operate on. Queries are defined using the defineQuery function.

const query = defineQuery([TransformComponent, GroupComponent])

const entities = query() // returns an array of entity numbers

Queries also have enter and exit derivatives, which are used to define when a combination of components is added or removed from an entity. These are defined using the defineEnterQuery and defineExitQuery functions.

const query = defineQuery([TransformComponent, GroupComponent])

const allEntities = query()
const enterEntities = query.enter()
const exitEntities = query.exit()

Examples

Timer

The follow code snippets, we define a component and a system. The component will hold a property to store the current elapsed time rounded down.

In the initializer of the system, it creates a new entity and adds the component to it. In the execute function of the system, we set the property time on the component of the entity.

This example uses 'Structure of Arrays' (SoA) data structures with bitECS syntax.

const TimerComponent = defineComponent({
name: 'TimerComponent',
schema: {
time: Types.f32
}
})

const timerQuery = defineQuery([TimerComponent])

const execute = () => {
const { deltaSeconds } = getState(EngineState)

for (const entity of timerQuery()) {
TimerComponent.time[entity] += delta
}
}

export const TimerSystem = defineSystem({
uuid: 'TimerSystem',
execute
})

This example uses 'Array of Structures' syntax, with reactive data binding.

const TimerComponent = defineComponent({
name: 'TimerComponent',
onInit: (entity) => {
return {
time: 0
}
},
onSet: (entity, component, json) => {
if (typeof json?.time === 'number') component.time.set(json.time)
},
toJSON: (entity, component) => {
return {
time: component.time.value
}
}
})

const timerQuery = defineQuery([TimerComponent])

const execute = () => {
const { elapsedSeconds } = getState(EngineState)

for (const entity of timerQuery()) {
const timerComponent = getMutableComponent(entity, TimerComponent)
timerComponent.time.set(Math.floor(elapsedSeconds))
}
}

export const TimerSystem = defineSystem({
uuid: 'TimerSystem',
execute
})

References

+ + + + \ No newline at end of file diff --git a/docs/creator/development/index.html b/docs/creator/development/index.html new file mode 100644 index 000000000000..ce79763582c2 --- /dev/null +++ b/docs/creator/development/index.html @@ -0,0 +1,16 @@ + + + + + +Development | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/creator/development/networking/index.html b/docs/creator/development/networking/index.html new file mode 100644 index 000000000000..a4c3ddfbef76 --- /dev/null +++ b/docs/creator/development/networking/index.html @@ -0,0 +1,16 @@ + + + + + +Networking | etherealengine + + + + +
+

Networking

Networks

Networks are a way of sharing topic specific data between certain peers. There are two types of networks, world and media networks, and are tied to location instances and media instances respectively.

Users & Peers

Users are unique accounts created in a particular Ethereal Engine deployment. Users can connect to multiple instances, and have multiple peers connected to each instance.

Ownership and Authority

Ownership specifies that a networked entity belongs to a particular user. Ownership cannot be transferred for an entity, the entity must be destroyed and recreated by a new user.

Authority specifies that a networked entity can be controlled by a particular peer. Authority can be transferred between peers, and is done so by sending an authority request action to the owner peer, upon which the owner peer will send an authority transfer action to the requesting peer.

+ + + + \ No newline at end of file diff --git a/docs/creator/development/projects_overview/index.html b/docs/creator/development/projects_overview/index.html new file mode 100644 index 000000000000..205e0870c10f --- /dev/null +++ b/docs/creator/development/projects_overview/index.html @@ -0,0 +1,50 @@ + + + + + +Projects | etherealengine + + + + +
+

Projects

Projects are folders that contain all your custom code, assets and scenes. They +are version controlled using git & github, and can be installed to any deployment +with a single click. (more on that in the next chapter)

Pictured below is an example of 4 projects installed. By default, only the +default-project is installed, which in a production environment is read only. +You can find the default project under /packages/projects/default-project/

In a production environment, the builder process will install all projects +according to the project database table and will download files from the +storage provider. In a local development environment, the local file system is +always the source of truth. Any project folders added or removed from the file +system will be automatically added or removed from the database. This is to +ensure there is no accidental loss of data, as these project folders are all git +repositories.

File Structure

Projects have a few conventions.

  • assets/ is where files uploaded from the editor will be uploaded to

  • src/ is where code assets can be served from

  • tests/ is where test files can be run

  • sceneName.scene.json is a scene file

  • sceneName.thumbnail.png is an auto-generated scene thumbnail file

  • xrengine.config.ts the project configuration, where client routes, database +models, feathers services and the project thumbnail can be defined

A project must also have a package.json to provide custom dependencies, and to define +the project name, project version, and Ethereal Engine version it is known to work with.

Systems imported from a scene MUST have their filename end with System.ts and be in the /src/systems folder. +This is to optimize vite's code-splitting bundling process, as each potentially dynamically +importable file will result in a new bundle with it's own copy of all of it's import dependencies.

@etherealengine/* monorepo dependencies will be symlinked and not needed, but some +package managers (such as pnpm) require these to be defined. If so, they should +be defined in peerDependencies and kept up to date with the current engine version.

Config

The ethereal engine config file has the following options:

export interface ProjectConfigInterface {
onEvent?: string
thumbnail?: string
routes?: {
[route: string]: {
component: () => Promise<{ default: (props: any) => JSX.Element }>
props?: {
[x: string]: any
exact?: boolean
}
}
}
webappInjection?: () => Promise<{ default: (props: any) => void | JSX.Element }>
worldInjection?: () => Promise<{ default: () => Promise<void> }>
services?: string
databaseSeed?: string
settings?: Array<ProjectSettingSchema>
}

Hooks

The onEvent property is a relative path string that points to a file which +must expose an object with properties as follows:

export interface ProjectEventHooks {
onInstall?: (app: Application) => Promise<any>
onLoad?: (app: Application) => Promise<any>
onUpdate?: (app: Application) => Promise<any>
onUninstall?: (app: Application) => Promise<any>
/**
* get oEmbed for active routes that match URL
* return that project's onOEmbedRequest()
* if null, return default
*/
onOEmbedRequest?: (app: Application, url: URL, currentOEmbed: OEmbed) => Promise<OEmbed | null>
}

These functions are called when the project they belong to are installed, +updated (such as scenes saved) or uninstalled respectively. This is used in the +default ethereal engine project to install the default avatars. +See /packages/projects/default-project/projectEventHooks.ts.

Thumbnail

This is a URL to a thumbnail for the project.

Routes

Routes enable users to customise the various URL paths of their website +utilising dynamic loading of modules. The key of each object represents the path +(with leading forward slash included) while the value represents a react +component object which gets wrapped in React.lazy() and a props object which +passes options into the react-dom-router Route component corresponding to the route.

Webapp Injection

Webapp injection allows logic to be run on all pages, loaded before any routes +are loaded. This will soon be extended to allow easy stylesheet injection and +other configurables of the webapp.

World Injection

World injection allows logic to be run every time a new world is created, +currently only when the engine is initialised. This is loaded on all instances +of the engine, such as a location and the editor. An example use case of this +would be registering custom scene loader and editor prefabs.

Services

The services property is a relative path that points to a file which must +return type ((app: Application) => Promise<any>)[] which is run on all +instanceservers and api servers at startup. This allows users to expose custom +Feathers services, or whatever other functionality they made need.

Database Seeding

The databaseSeed property is a relative path that points to a file which must +return type ServicesSeedConfig from ../packages/common/src/interfaces/ServicesSeedConfig.ts +which is run when the database seeder is run.

i18n

Internationalization can be added using the pattern ./i18n/<language>/<namespace>.json. An example of the format can be found in the base i18n files.

+ + + + \ No newline at end of file diff --git a/docs/creator/development/state_management/index.html b/docs/creator/development/state_management/index.html new file mode 100644 index 000000000000..00d9c7ce1b2d --- /dev/null +++ b/docs/creator/development/state_management/index.html @@ -0,0 +1,16 @@ + + + + + +State Management | etherealengine + + + + +
+

State Management

All of Ethereal Engine's state management uses hookstate and react. Together, these tools give reactive, declarative, and controlled state management across any scope.

Scoped State

Scoped state can be defined using the useHookstate hook - this is vanilla hookstate, and is useful for state that is only used in a single component, or state that is only used in a single component tree.

import { useHookstate } from '@hookstate/core'

const MyComponent = () => {
const state = useHookstate({
count: 0
})
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => state.count.set(state.count.get() + 1)}>Increment</button>
</div>
)
}

Global State

Global state definitions are wrapped in a 'store' which allows for automatic creation and cleanup as needed. This API as well as the underlying hookstate API can be imported from @etherealengine/hyperflux.

MyState.ts
import { defineState } from '@etherealengine/hyperflux'

const MyState = defineState({
name: 'MyState',
initial: {
count: 0
}
})

Global state will be registered to the engine instance once it has been called with getState or getMutableState. This will cause the state to be created if it does not exist, and will be cleaned up when the engine instance is destroyed.

It's proxy can be accessed with Engine.instance.store.stateMap.MyState where MyState is the name of the state.

When accessing the state, getState returns the underlying object typed as readonly. This is useful for reading state values, but should not be used to write to state.

import { getState } from '@etherealengine/hyperflux'
import { MyState } from './MyState'

const state = getState(MyState)
console.log(state.count) // 0
state.count = 1 // Error: Cannot assign to 'count' because it is a read-only property.

State can be mutated via the getMutableState function, which returns a proxy to the state, which can be used to read and write state values. The proxy is reactive, so any changes to the state will cause the component to re-render.

The proxy returned can be wrapped in hookstate's reactive hook useHookstate. This will cause the component to re-render when any state values are changed.

import { getMutableState, useHookstate } from '@etherealengine/hyperflux'
import { MyState } from './MyState'

const MyComponent = () => {
const state = useHookstate(getMutableState(MyState))
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => state.count.set(state.count.get() + 1)}>Increment</button>
</div>
)
}
+ + + + \ No newline at end of file diff --git a/docs/creator/importing_assets/index.html b/docs/creator/importing_assets/index.html new file mode 100644 index 000000000000..b4c548ba3514 --- /dev/null +++ b/docs/creator/importing_assets/index.html @@ -0,0 +1,18 @@ + + + + + +Asset Import Pipeline | etherealengine + + + + +
+

Asset Import Pipeline

Omniverse

Unity

Unreal

Blender

WARNING: This page is out of date

The simplest pipeline uses Blender & the Studio's inbuilt transformation tool.

Scenes that contain colliders should have these colliders exported separately. +Visible meshes should not have collider metadata, instead a copy should be created.

The process of moving from Blender to Ethereal Engine looks like the following:

  1. Blend file is the source of truth
  2. Export visible meshes from from blend file
  3. Export collider meshes from blend file with Custom Properties
  4. Import to editor
  5. Optimize visible glb with transformation tool
  6. Use final transformed visible glb & collider glb for live scene

Collider Metadata

All fixed colliders should be a child of a separate root hierarchy.

The root object of the collider hiearchy must have xrengine.collider.bodyType: Fixed +Each collider must be a child of the root object with shapeType: <shape>

The currently supported shapes are as follows:

  • Cuboid
  • Ball
  • Capsule
  • Cylinder
  • ConvexPolyhedron
  • TriMesh

Other supported metadata for each collider is:

  • friction: number
  • restitution number
  • collisionLayer: number
  • collisionMask: number
  • isTrigger: number
+ + + + \ No newline at end of file diff --git a/docs/creator/index.html b/docs/creator/index.html new file mode 100644 index 000000000000..86c4ba5dbe1e --- /dev/null +++ b/docs/creator/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal for Creators | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/creator/studio/index.html b/docs/creator/studio/index.html new file mode 100644 index 000000000000..aa27e6e89012 --- /dev/null +++ b/docs/creator/studio/index.html @@ -0,0 +1,194 @@ + + + + + +Studio Overview | etherealengine + + + + +
+

Studio Overview

Ethereal Engine Studio +UI Overview +image6

1: Toolbar

2: Scene and File Directory

3: Preview

4: Viewport

5: Hierarchy, Material Library, Node Graph

6: Properties

7: Assembly Menu

8: User Profile


1 Toolbar

1. File Menu

Create new scenes, import files, and save or export existing scenes.

2: Advanced

Toggle advanced options on Model or Avatar components. +Add and remove components in the Properties tab

3. Active Instances

Active Instances shown here

4. Transform Gizmo: Scale, Rotate, Move

[ Y ] Scale +[ R ] Rotate +[ T ] Move

  1. World Space or Object Space Transform - toggle to world or object +Sets your transform control to be oriented to the object(selection) or world +World space relates to the entire scene’s orientation +Object space (your selection) relates to transforms made to a specific object in relationship to the world space

[ Z ] Toggle World space or Object(Selection) space

  1. Toggle Transform Pivot - modes: Selection, Center, Bottom, or Origin +To use, shift select objects, enter transform mode (Y, R, T), choose pivot type: +Selection:the center pivot of the final asset you selected in the sequence +Center: a pivot that sits at an equal distance between all selections +Bottom: pivot that sits equally between all selections and at the bottom of your final selection in the sequence +Origin: sets pivot mode to the world origin (0,0,0) +*it is recommended to use the Toggle Transform in conjunction with the World/Object Space transforms

[ X ] Toggle between Selection, Center, or Bottom +[ E ] incrementally rotate around the Y axis, adopts the selected snapping degree value

  1. Grid Snapping (toggle) +Transform objects by a unit of measurement [.1 meters, .125 meters, 1 meter, 4 meters, etc] +Rotate objects by a specific degrees [5o,10o, 20o, 90o, etc]

[ C ] Toggle Snap Mode +[ E ] incrementally rotate around the Y axis, adopts the selected snapping degree value

  1. Grid Visibility (toggle) +Set grid spacing by meters
  1. Render Mode +How you view materials in the Engine +(Unlit, Lit, Shadows, Wireframe, Normals)
  1. Preview Scene +Spawns you into the scene
  1. Status (toggle)

Show stats about the scene and gives you a clue as to how optimized your scene is +Memory: Geometries, Textures +Render: FPS, Frame Time, Calls(drawcalls), Triangles, Points, Lines

  1. Helpers (toggle) +View hidden information about your scene, ie: colliders
  1. Node Helpers (toggle) +Helper geometry that helps components have visibility in the scene when inactive
  1. Take A Screenshot +Takes a screenshot of your scene at the current view

#2 Scene and File Directory

Project Files +Contains all files associated with your project. +.json files and various other file types in this menu are your project files and will show up automatically when you create a new scene.

Assets folder +Contains all assets you can import into your scene. When you use the Toolbar: File Menu to import files, they are delivered directly to the assets folder. To populate your scene simply drag them from the assets directly to your hierarchy. +Tip: Import may create a transform offset +When some assets are loaded they automatically show up in the scene in the hierarchy and sometimes at an offset. Simply delete them from the hierarchy and re-drag them from your assets folder into your scene hierarchy to have them be set at home (0,0,0)

#3 The Preview Panel +The preview panel allows you to preview certain files, currently supporting image, video and audio files

#4 Viewport +The view of all things active inside your scene. +Objects have the typical navigation controls +X = red +Y = green +Z = blue

#5 Hierarchy & Material Library +Hierarchy +The scene Hierarchy contains all element currently in your scene (assets, lighting, items from the tool menu, etc) +Material Library +Location of an assets materials and where you can select and edit them

#6 Properties +Where you can access and edit detailed information about objects in your scene. +Select an object in the Hierarchy to view its Properties. This panel supports editing and adding actions to objects, ie: keying transforms, turning on animation tracks, looping motion, and adding components to objects

Model URL +Shows the location of an object in your scene hierarchy

Using the Advanced Tab (toolbar) +By activating the advanced tab from the toolbar you are able to add specific components to assets in your scene adding data to the entity. +Explode objects that are imported as a collapsed group

Types of Components

#7 Assembly Menu

Files +Model +Creates objects in the hierarchy. Drag a model from the assets folder into the URL box or drag assets directly from project files into the hierarchy +Volumetric +Import volumetric files. Accepts DRCS, UVOL, or Manifest Files, links to cloud hosting +Video +2D plane accepts .mp4 .mkv .avi +Audio +Import audio clips, .mp3, .flac, .ogg, .wav, .m4a

Scene Composition +Ground Plane +Create collision ground plane +Group +Collection of models or assets +Asset Prefab +Create prefabs from groups or objects that are saved to the assets folder. Saving requires specific naming: 'assetName'.xre.gltf +Collider +Creates a collision ball, cuboid, capsule, or cylinder to be manually placement

Interaction +Spawn Point +A point where people will appear when they enter your scene +Portal +A portal to teleport a player to a port in a different location

Lights +Hemisphere Light +A light which illuminates the scene from directly overhead +Point Light +A light which emits in all directions from a single point +Directional Light +Creates a light that emits evenly in a single direction +Ambient Light +A combination of direct and indirect light, provides general lighting to all assets +Spot Light +Creates a light that shines in a specific direction

Scripting +Inserts code into the scene by creating a new Entity Component System based on the provided .ts file

FX +Ocean +Cube body of water +Particle Emitter +Creates a particle emitter +Cloud +Sprite based cloud volume +Water +Creates a circular water surface with ripple effect +Spline +Create and customize curves

Misc +E-commerce shop +Create a shop, choose product from dropdown, click select product, click away, click back, select product item(.glb), select variant, select product, click away, click back, object will populate scene

#8 User Profile
+Your Ethereal Engine account settings and linked account information

The settings wheel icon allows you to turn up your scene resolution. +If you notice the scene looks blurry, go to the Graphics tab inside Settings and turn the Resolution tab all the way up.

Create a Project +Import Assets +You can use the File menu to import assets or you can drag and drop them into the assets folder, when clicking and dragging notice a slight change in the color of the Engine, this signifies the engine is ready to ingest your file. +Importing assets immediately creates them in the scene at an arbitrary location when imported via the viewport. It is recommended to delete that import and drag an asset directly from project files into the hierarchy to easily zero out your transforms. +Ethereal Engine accept the following file types

3D Models .glb, .gltf +Images .png, .tiff, .jpeg +Volumetric DRCS, UVOL, Manifest Files on the Cloud +Videos .mp4m, .mkv, .avi +Audio .mp3, .mpeg, .m4a +Save Project +In the File menu, click the save or save as button to save your scene +Some projects require time to save so don't exit this window until a few minutes have passed +Edit Materials +Ethereal Engine supports a PBR workflow and Vertex Colors +PBR Workflow: +Diffuse or Base Color Map +Metalness Map +Roughness Map +Normal Map +Ambient Occlusion (AO) Map +*each of these loaded will represent one draw call, only use maps you absolutely need. You can drop the diffuse map and use our built in RGB color selector to save scene space.

Your asset materials are visible in the order below under the Material Library tab +Material Library

Asset Name +material name +material name +material name

Material Types: +MeshBasicMaterial +This material is not affected by lights. +https://threejs.org/docs/?q=meshba#api/en/materials/MeshBasicMaterial

MeshStandardMaterial +A standard physically based material, using Metallic-Roughness workflow. +https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial

MeshMatcapMaterial +MeshMatcapMaterial is defined by a MatCap (or Lit Sphere) texture, which encodes the material color and shading. +MeshPhysicalMaterial +An extension of the MeshStandardMaterial, providing more advanced physically-based rendering +(added properties include: Clearcoat, Physically-based transparency, Advanced reflectivity, and Sheen) +MeshLambertMaterial +A material for non-shiny surfaces, without specular highlights. +MeshPhongMaterial +A material for shiny surfaces with specular highlights. +MeshToonMaterial +A material implementing toon shading. +ShaderMaterial +https://threejs.org/docs/?q=shadermat#api/en/materials/ShaderMaterial +ShadowMaterial +https://threejs.org/docs/?q=shadow#api/en/materials/ShadowMaterial

Saving Changes +Anytime you make a change to a model, you need to save your change. +This includes edits to the Position, Rotation, Scale, Normals, UVs, Materials and Attributes. +After making your edit, go to the hierarchy and re-select your asset, in the Properties tab, scroll to the bottom and click the Save Changes button. If you want to Save As, in the url just above the Save Changes button, you can manually edit the name at the end of the url and click Save Changes. You can find the new version of your .glbl in the assets folder.

Tip: Convert .gltfs or .usdz to .glb format in the engine using this method +Compression +The in-engine compression menu is available when you select the model you want to run compression on from the Hierarchy. Scrolling down inside of the Properties panel you can expand the Model Transform Properties Menu. +There are three menus, gltF-Transform, Delete Attributes, Bake To Vertices.

gltF-Compression: +Runs compression on the models geometry and image textures. Default settings work well for most models. +The Image Format menu allows you to either choose JPG, KTX2, or PNG for the image’s compression format. +The Max Texture Size denotes the pixel scale of your image. Default settings downsize the textures to 1024 pixels x 1024 pixels +Press Optimize to run the compression

Delete Attributes: +Models occasionally are imported with an excess of attributes taking up unwanted space, to delete the extra, unnecessary data list the attributes here with a space in between each attribute listed

Bake To Vertices: +This tool bakes your texture to vertex color. By doing this we can eliminate the need for loading heavy images on some models. Vertex Baking transfers your PBR maps to the vertex of your model. We currently support diffuse, lightMap and emissive. +*this method is for models that have a simple texture with either a single color or few details

Animations in Objects +Avatars +To turn on the animations of an imported model you would like to use as an avatar, in the Loop Animation tab you can select the animation track you wish to activate, “mixamo.com”. +Loop Animations: loop the motion tracks available on your avatar +Checking ‘Is Avatar’ allows you to use the animations built into the engine on your Avatar.

Animated Geometry +Loop Animations: loop the motion tracks available on your model

Skybox/Cubemap +The Skybox Button from the Tools Panel allows you to create a Skybox for your scene. +You can choose between Color, Skybox, Cubemap, and Equirectangular +Color: basic color as the sky +Skybox: cubemap that surrounds your scene giving the look of being in an environment +Equirectangular: sphere that surrounds your scene giving the look of being in an environment, recommended sources for equirectangular images are hdrihaven.com or

Tip: HdriHaven has great free HDRI Resources

Importing individual models (.glb/.gltf & .usdz) +Import your model via the File Menu or drag and drop into the Viewport (when viewport changes color it is ready to ingest the file) +With the model in your Hierarchy, select it and scroll down in its Properties tab. +Re-name to your desired description with a .glb or .gltf extension. You can find your saved model in your Assets tab in the Project Files directory +scene should be determined by what your scene is composed of. Successful optimization is achieved by leveraging the appropriate use of detail per model. +Converting Models to .glb (recommended) +Convert .gltf to a .glb (in browser) +Recommended to convert .gltf into .glbs for easier importing +https://glb-packer.glitch.me/ +https://cartmagician.com/tools/3d-to-AR-converter (paid) +Convert .fbx to .glb (app) +https://github.com/facebookincubator/FBX2glTF +Convert .usd to .gltf (in browser) +https://products.groupdocs.app/conversion/usd-to-gltf

Using SampleStandardMaterial to enhance projects +Custom settings for Glass, Plastic, Glow & Metal are provided below

For the MeshStandardMaterial +(re-create values below to simulate materials on your geometry) +https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial

Glass Plastic Glow Metal

Tip: Exporting assets for basic materials +It is not required to have a texture map on all assets in 3D and it is recommended to use Standard Materials as often as possible. We recommended using basic materials for all basic metal, glass, emissive, and plastic assets (follow the sample material set-up above). You must denote which assets will have Standard Materials before you import your .glb to the engine. It is recommended to simply drag a native material from your chosen DCC or game engine prior to export, correctly name the basic material before exporting the .glb. Names given before import are the names the engine will inherit.

Saving Your Project

Save As or Save Scene can be found in the File Menu. +Allow the Engine a few minutes to save your file. +Tip: Change the view to create a thumbnail +You will be asked to create a thumbnail on Save which takes a screenshot from the current viewport view. Move your viewport to look at the desired view for your thumbnail before you click Save.

+ + + + \ No newline at end of file diff --git a/docs/creator/testing/debugging/index.html b/docs/creator/testing/debugging/index.html new file mode 100644 index 000000000000..8b7518e56d30 --- /dev/null +++ b/docs/creator/testing/debugging/index.html @@ -0,0 +1,16 @@ + + + + + +Debugging | etherealengine + + + + +
+

Debugging

This section covers different techniques for debugging the source code.

Basic Debugging

This config can be used to debug instance server & backend server code. Navigate to 'Run & Debug' tab of vscode.

  1. Add a breakpoint to desired line of code.

  2. Select 'Debug Dev' from debug config dropdown.

  3. Hit the run/play button to start debugging.

  4. Breakpoint will be hit as the code executes that line of code.

Below image further elaborates this.

Basic Debug Image

+ + + + \ No newline at end of file diff --git a/docs/creator/testing/debugging_deployed_instanceservers/index.html b/docs/creator/testing/debugging_deployed_instanceservers/index.html new file mode 100644 index 000000000000..81e19cc9fdba --- /dev/null +++ b/docs/creator/testing/debugging_deployed_instanceservers/index.html @@ -0,0 +1,32 @@ + + + + + +Debugging Deployed Instanceservers (and other Kubernetes pods) | etherealengine + + + + +
+

Debugging Deployed Instanceservers (and other Kubernetes pods)

Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear +before one has a chance to view them, as the pods that they were on are deleted, along with their logs.

One way to catch these errors is to tail the logs of existing pods from a local machine and then trigger the error. +The tail of the logs will persist in your terminal even after the pod has been deleted.

You should already have kubectl set up and pointing to your cluster, but if not, do so. +(see here for links to do that) +Make sure you don't have a browser tab with the offending location(s) open already, as you want to be tailing +the logs before the instance starts.

Next, run kubectl get gs. If the cluster is fully installed, this will get all of the running instanceserver +pods (kubectl get pods will get all pods, if you need to find the names of API pods, etc.) +Select the Name of a pod and copy it (in Linux, highlight it and press CTRL+SHIFT+C), then run +kubectl logs <pod_name> -c <RELEASE_NAME>-instanceserver -f, +e.g. kubectl logs prod-instanceserver-vhwh2-9vqrv -c prod-instanceserver -f. It should output something like this for +and instanceserver pod:

> @etherealengine/instanceserver@1.3.0 start
> cross-env APP_ENV=production ts-node --swc src/index.ts

👾 bitECS - resizing all data stores from 100000 to 5000
Powered by three.quarks. https://quarks.art/
[hyperflux:Action] Added topic default
[hyperflux:State] registerState SceneState
[hyperflux:Action] Added Receptor EngineEventReceptor
[hyperflux:State] registerState EngineState
[hyperflux:State] registerState ServerState
Tue, 11 Jul 2023 00:38:50 GMT koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md at ../../node_modules/@feathersjs/koa/lib/index.js:52:27
[00:38:50.631] INFO: Starting app.
component: "server-core:sequelize"
[hyperflux:State] registerState NetworkState
[00:38:50.645] INFO: Starting app.
component: "server-core:mysql"
[00:38:50.900] INFO: registered kickCreatedListener
component: "instanceserver:channels"
[00:38:50.901] INFO: Starting instanceserver with NO HTTPS on 3031, if you meant to use HTTPS try 'sudo bash generate-certs'
component: "instanceserver"
[00:38:51.036] INFO: Feathers-sync started.
component: "server-core"
[00:38:51.634] INFO: Server Ready
component: "server-core:sequelize"

Since the instanceserver pod that is picked to handle a given world or media instance is random, you'll want to +open a few more tabs in your terminal and repeat the above kubectl logs command, substituting a different +instanceserver pod name in each tab, so that you're tailing all of the current pods. Then go to the location that is +displaying problematic behavior, or otherwise trigger the action that is causing problems, and you should see the error +in one of the terminals. If it's a fatal error, the logging will end with the pod, but the logs will stay in that terminal.

Note that if you want to log further errors, you may need to get the names of the new pods that are spun up to replace +the ones that crashed by running kubectl get gs or kubectl get pods again, and then using the new pods' names in +kubectl logs commands.

+ + + + \ No newline at end of file diff --git a/docs/creator/testing/debugging_device_wsl/index.html b/docs/creator/testing/debugging_device_wsl/index.html new file mode 100644 index 000000000000..26c43059ea63 --- /dev/null +++ b/docs/creator/testing/debugging_device_wsl/index.html @@ -0,0 +1,21 @@ + + + + + +Debugging Engine in WSL on Phone/Headset | etherealengine + + + + +
+

Debugging Engine in WSL on Phone/Headset

This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11.

  1. Ensure that your .env.local and database entries points to localhost.

  2. Open a location i.e. https://localhost:3000/location/apartment through Windows 11 chrome. It should work fine.

  3. Connect your device (currently tested on Samsung S22 Ultra) with PC and enabled USB debugging and access prompts as mentioned on https://developer.chrome.com/docs/devtools/remote-debugging/

  4. Once your device is connected, then you can see your device's browser tabs in PC's Chrome as show in below image. chrome://inspect/#devices +Device connected to PC Chrome

  5. Make sure the check boxes marked in below are checked. +Remote Devtool Options

  6. Click on "Port forwarding" button and ensure you have entries as shown in below image. Also make sure to check the port forwarding checkbox in that modal. +Port Forwarding Options

  7. Once this is done and you have Port forwardings having green circles before them which means forwarding is working as shown in below image. +Port Forwarding Enabled

  8. Navigate to https://localhost:3000/location/apartment in your device's browser.

  9. On your PC you can inspect this and allow if you face any certificate errors as shown in below image. +Remote Debugging

+ + + + \ No newline at end of file diff --git a/docs/creator/testing/index.html b/docs/creator/testing/index.html new file mode 100644 index 000000000000..3103a238eae5 --- /dev/null +++ b/docs/creator/testing/index.html @@ -0,0 +1,22 @@ + + + + + +Testing | etherealengine + + + + +
+

Testing

Automated testing is a cornerstone to successful software development. Tests are +not just to ensure that your application is working as intended, they are also +to ensure that existing features aren't broken by any newly introduced features +or code, aka regression bugs. The latter tends to hold more value, as it +makes the software sturdy and less prone to these types of bugs during active +development of a project. Regression bugs will quickly stall the development of +a project at a certain level of complexity, effectively preventing progress.

SMTP Testing

https://mailtrap.io/inboxes

Add credentials in .env.local

SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=2525
SMTP_USER=<mailtrap-user>
SMTP_PASS=<mailtrap-password>

Unit tests

Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:

const add2 = x => x + 2

it('should add 2 to a given number', () => {
strictEqual(add2(1), 3)
})

Integration tests

Integration tests focus on testing bundles of code units. A composition of functions, for example:

const addTwo = x => x + 2
const multThree = x => x * 3
const halve = x => x / 2

const algorithm = x => {
x = addTwo(x)
x = multThree(x)
x = halve(x)
return x
}

it('should apply the entire algorithm correctly', () => {
strictEqual(algorithm(4), 9)
})

Unit vs Integration Tests (source)

Unit TestingIntegration Testing
In unit testing each module of the software is tested separately.In integration testing all modules of the the software are tested combined.
In unit testing the tester knows the internal design of the software.In integration testing the tester doesn't know the internal design of the software.
Unit testing is performed first of all testing processes.Integration testing is performed after unit testing, and before system/end-to-end tests.
Unit testing is a white box testing.Integration testing is a black box testing.
Unit testing is performed by the developer.Integration testing is performed by the tester.
Detection of defects in unit testing is easy.Detection of defects in integration testing is difficult.
It tests parts of the project without waiting for others to be completed.It tests only after the completion of all parts.
Unit testing is less costly.Integration testing is more costly.

System tests

System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test).

End-to-end tests

End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow).

System vs End-to-end Tests (source)

System TestingEnd-to-end Testing
In system testing, whole software or application is tested at a time.In end-to-end testing, behavioral flow of the software is tested.
System testing only tests the specific software system.It tests the software system and the connected systems both.
The functionality of the software is tested.Flow from end-to-end is tested.
It validates the software system as per standards and specifications.It validated all the interfaces of the software.
Knowledge of interconnected systems is not required.Knowledge about interconnected systems is required.
It is carried out once integration testing is performed.It is performed after the system testing.
It is performed both manually and automated.It is generally performed manually.
It is the super set of end-to-end testing.It is considered as subset of the system testing.

White-box vs Black-box testing

Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing.

Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing.

The Testing Pyramid

A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution.

70% Unit tests

20% Integration tests

10% End-to-end tests

        /```\
/ E2E \
/_______\
/ \
/Integration\
/_____________\
/ \
/ Unit \
/___________________\
+ + + + \ No newline at end of file diff --git a/docs/creator/testing/reasonable_code/index.html b/docs/creator/testing/reasonable_code/index.html new file mode 100644 index 000000000000..0595d7a1a4bc --- /dev/null +++ b/docs/creator/testing/reasonable_code/index.html @@ -0,0 +1,16 @@ + + + + + +Writing Reasonable & Testable Code | etherealengine + + + + +
+

Writing Reasonable & Testable Code

Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application.

In the functional programming (FP) paradigm, pure functions are functions which do not mutate any existing state of any scope. Since we are not in a fully functional paradigm, a focus on these qualities of functions can be priceless: stateless functions with referential transparency.

Stateless means that the function itself has no memory of the past. Referential transparency means that the function is only operating on the parameters, and nothing else (no global state access, etc).

These types of functions may (arguably) mutate parameter state, but may only operate on the given parameters. State residing outside of the scope of a stateless function should never be depended on or mutated. This will ensure that the function holds no inherent state of its own, and therefore will exhibit the behavior of being referentially transparent and idempotent.

Idempotency is a quality of any function which can be executed several times without changing the output for a specific input. Idempotent functions can be thought of as mappings from one input to one output.

All of this combined makes functions extremely simple to reason about, very reusable, and easy to test! Three gulls, one scone.

Example

Here is an example of a function that does not exhibit referential transparency, nor is it stateless:

let y = 3
const someFunction = x => {
x += y
y++
return x
}

someFunction(3) // => 6
someFunction(3) // => 7
someFunction(3) // => 8

This function is also not idempotent. Same input, different output! Not good for reasonable code, difficult to predict.

Written as a stateless, idempotent function with referential transparency:

const someFunction = (data, x) => {
x += data.y
data.y++
return x
}

someFunction({ y: 3 }, 3) // => 6
someFunction({ y: 3 }, 3) // => 6
someFunction({ y: 3 }, 3) // => 6

The newly written function now holds no inherent state of its own and does not operate on any data that was not passed into the function as explicit arguments. It is also idempotent: same input, same output! Very reasonable and easy to predict.

Code Composition / Decomposition

We must now capture the process of decomposing a program into smaller pieces that are more reusable, more reliable, and easier to understand. Then we can combine each individual piece to form an entire program that is easier to reason about as a whole. FP tends to follow this fundamental principle.

FP falls under the umbrella of declarative programming paradigms: it expresses a set of operations without revealing how they’re implemented or how data flows through them. Unlike imperative programming, declarative programming separates program description from evaluation. It focuses on the use of expressions to describe what the logic of a program is without necessarily specifying its control flow or state change.

These two paradigms can be utilized to form powerful and extremely testable functions and compositions which support a sturdy codebase. Write functions imperatively, then compose them together declaratively!

Example

Using the previous unit/integration test examples, lets see what the algorithm would look like if written imperatively:

const algorithm = x => {
// first, add two
x += 2
// then, multiply by three
x *= 3
// finally, divide by two
x /= 2
return x
}

Rewritten declaratively, as demostrated before but with a newly introduced pipe function (a standard function in FP):

const addTwo = x => x + 2
const multThree = x => x * 3
const halve = x => x / 2

const algorithm = pipe(addTwo, multThree, halve)

algorithm(4) // => 9

As you can see, the imperative function has no reusable parts, but the declarative version does! This is a simple example, but in larger-scale functions and systems this simple distinction can be a powerful tool in writing reasonable, testable, and reusable code. Bonus: the code is self documenting. No need for comments here. Just pure, self-descriptive functions!

+ + + + \ No newline at end of file diff --git a/docs/creator/testing/test_driven_development/index.html b/docs/creator/testing/test_driven_development/index.html new file mode 100644 index 000000000000..e02f305d7fd4 --- /dev/null +++ b/docs/creator/testing/test_driven_development/index.html @@ -0,0 +1,16 @@ + + + + + +Writing Good Tests | etherealengine + + + + +
+

Writing Good Tests

Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:

  1. Mock
  2. Run
  3. Assert

First, mock up data for the input parameters.

Then, run the function with the input data to produce an output.

Finally, assert that the output is correct.

Test-Driven Development (source)

Test-driven development (TDD) is a software development process relying on software requirements being converted to test cases before software is fully developed, and tracking all software development by repeatedly testing the software against all test cases. This is as opposed to software being developed first and test cases created later.

This methodology is extremely useful and productive, because it means that your code will always have test coverage. Not only that, but you can save time by ensuring that the feature is working simply by virtue of the tests passing, instead of having to run the entire software to see whether or not the feature or module in question is functioning correctly.

The following sequence is based on the book Test-Driven Development by Example:

  1. Add a test

    The adding of a new feature begins by writing a test that passes if and only if the feature's specifications are met. The developer can discover these specifications by asking about use cases and user stories. A key benefit of test-driven development is that it makes the developer focus on requirements before writing code. This is in contrast with the usual practice, where unit tests are only written after code.

  2. Run all tests. The new test should fail for expected reasons

    This shows that new code is actually needed for the desired feature. It validates that the test harness is working correctly. It rules out the possibility that the new test is flawed and will always pass.

  3. Write the simplest code that passes the new test

    Inelegant or hard code is acceptable, as long as it passes the test. The code will be honed anyway in Step 5. No code should be added beyond the tested functionality.

  4. All tests should now pass

    If any fail, the new code must be revised until they pass. This ensures the new code meets the test requirements and does not break existing features.

  5. Refactor as needed, using tests after each refactor to ensure that functionality is preserved

    Code is refactored for readability and maintainability. In particular, hard-coded test data should be removed. Running the test suite after each refactor helps ensure that no existing functionality is broken.

    Examples of refactoring:

    • moving code to where it most logically belongs
    • removing duplicate code
    • making names self-documenting
    • splitting methods into smaller pieces
    • re-arranging inheritance hierarchies

The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply undo or revert rather than debug excessively. When using external libraries, it is important not to write tests that are so small as to effectively test merely the library itself, unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development.

Antipatterns

Practices to avoid, or "anti-patterns"

  • Having test cases depend on system state manipulated from previously executed test cases (i.e., you should always start a unit test from a known and pre-configured state).
  • Dependencies between test cases. A test suite where test cases are dependent upon each other is brittle and complex. Execution order should not be presumed. Basic refactoring of the initial test cases or structure of the UUT causes a spiral of increasingly pervasive impacts in associated tests.
  • Interdependent tests. Interdependent tests can cause cascading false negatives. A failure in an early test case breaks a later test case even if no actual fault exists in the UUT, increasing defect analysis and debug efforts.
  • Testing precise execution behavior timing or performance.
  • Building "all-knowing oracles". An oracle that inspects more than necessary is more expensive and brittle over time. This very common error is dangerous because it causes a subtle but pervasive time sink across the complex project.
  • Testing implementation details.
  • Slow running tests.
+ + + + \ No newline at end of file diff --git a/docs/creator/testing/testing_intro/index.html b/docs/creator/testing/testing_intro/index.html new file mode 100644 index 000000000000..3dd2f3adf294 --- /dev/null +++ b/docs/creator/testing/testing_intro/index.html @@ -0,0 +1,22 @@ + + + + + +Testing Basics | etherealengine + + + + +
+

Testing Basics

Testing

Automated testing is a cornerstone to successful software development. Tests are +not just to ensure that your application is working as intended, they are also +to ensure that existing features aren't broken by any newly introduced features +or code, aka regression bugs. The latter tends to hold more value, as it +makes the software sturdy and less prone to these types of bugs during active +development of a project. Regression bugs will quickly stall the development of +a project at a certain level of complexity, effectively preventing progress.

SMTP Testing

https://mailtrap.io/inboxes

Add credentials in .env.local

SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=2525
SMTP_USER=<mailtrap-user>
SMTP_PASS=<mailtrap-password>

Unit tests

Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:

const add2 = x => x + 2

it('should add 2 to a given number', () => {
strictEqual(add2(1), 3)
})

Integration tests

Integration tests focus on testing bundles of code units. A composition of functions, for example:

const addTwo = x => x + 2
const multThree = x => x * 3
const halve = x => x / 2

const algorithm = x => {
x = addTwo(x)
x = multThree(x)
x = halve(x)
return x
}

it('should apply the entire algorithm correctly', () => {
strictEqual(algorithm(4), 9)
})

Unit vs Integration Tests (source)

Unit TestingIntegration Testing
In unit testing each module of the software is tested separately.In integration testing all modules of the the software are tested combined.
In unit testing the tester knows the internal design of the software.In integration testing the tester doesn't know the internal design of the software.
Unit testing is performed first of all testing processes.Integration testing is performed after unit testing, and before system/end-to-end tests.
Unit testing is a white box testing.Integration testing is a black box testing.
Unit testing is performed by the developer.Integration testing is performed by the tester.
Detection of defects in unit testing is easy.Detection of defects in integration testing is difficult.
It tests parts of the project without waiting for others to be completed.It tests only after the completion of all parts.
Unit testing is less costly.Integration testing is more costly.

System tests

System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test).

End-to-end tests

End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow).

System vs End-to-end Tests (source)

System TestingEnd-to-end Testing
In system testing, whole software or application is tested at a time.In end-to-end testing, behavioral flow of the software is tested.
System testing only tests the specific software system.It tests the software system and the connected systems both.
The functionality of the software is tested.Flow from end-to-end is tested.
It validates the software system as per standards and specifications.It validated all the interfaces of the software.
Knowledge of interconnected systems is not required.Knowledge about interconnected systems is required.
It is carried out once integration testing is performed.It is performed after the system testing.
It is performed both manually and automated.It is generally performed manually.
It is the super set of end-to-end testing.It is considered as subset of the system testing.

White-box vs Black-box testing

Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing.

Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing.

The Testing Pyramid

A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution.

70% Unit tests

20% Integration tests

10% End-to-end tests

        /```\
/ E2E \
/_______\
/ \
/Integration\
/_____________\
/ \
/ Unit \
/___________________\
+ + + + \ No newline at end of file diff --git a/docs/creator/tutorials/ethereal_engine/index.html b/docs/creator/tutorials/ethereal_engine/index.html new file mode 100644 index 000000000000..8fd39441bbd3 --- /dev/null +++ b/docs/creator/tutorials/ethereal_engine/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal Engine | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/creator/tutorials/ethereal_engine/unity_bridge/index.html b/docs/creator/tutorials/ethereal_engine/unity_bridge/index.html new file mode 100644 index 000000000000..8f448bcc3d0a --- /dev/null +++ b/docs/creator/tutorials/ethereal_engine/unity_bridge/index.html @@ -0,0 +1,16 @@ + + + + + +Unity Bridge | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/creator/tutorials/ethereal_engine/unreal_bridge/index.html b/docs/creator/tutorials/ethereal_engine/unreal_bridge/index.html new file mode 100644 index 000000000000..0b8922bb60b2 --- /dev/null +++ b/docs/creator/tutorials/ethereal_engine/unreal_bridge/index.html @@ -0,0 +1,18 @@ + + + + + +Unreal Bridge | etherealengine + + + + +
+

Unreal Bridge

Ethereal Engine Bridge - Unreal

https://github.com/etherealengine/XRE-Bridge-Unreal

Unreal SDK Ethereal Engine Alpha

  • User Management API
  • Server Party Matchmaker
  • Unreal Game Server Lifecycle System
  • Unreal Blueprints Ethereal Engine SDK

CMS and marketplace services coming soon

EXAMPLE https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example

Screenshot 2022-06-06 193750

Setup

This guide assumes you have a working linux dedicated server build of you game.

Preinstall Requirements

Containerization details

Configuring gameserver

register a process with ENV VARS or Unreal executable arguments

https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/CommandLineArguments/

TroveServer.exe IslandLobby.uproject /Trove/Maps/Island1?game=MyGameInfo?listen -lobbygame -server 127.0.0.1
TroveServer.exe IsleOfDeath.uproject /Trove/Maps/IsleOfDeathStart?game=MyGameInfo?listen -stakedgame -server 127.0.0.1

VaREST and wrapping the Ethereal Engine Web API

knowledge required: Learn REST APIs, OpenAPI, Header based http auth, Verbs:Get/Post/etc, paylods, json

image

Targeting support for 4.26 and 4.27

Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal

https://github.com/etherealengine/XRE-Bridge-Unreal/

This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine

https://api-dev.etherealengine.com/openapi/

This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!

This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database

Screen Shot 2022-06-04 at 4 25 43 PM

Blueprints multiplayer Unreal reference

https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/

All K8 control plane systems can be access via rest calls to the local network of the gameserver, the functionality of Agones can be done via adding a node in Blueprints.

The Ethereal Engine matchmaker service exposes the default endopints for open match.

https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/01-open-match-core.yaml +https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/07-open-match-default-evaluator.yaml

REST API local call access docs

https://open-match.dev/site/docs/guides/access/

This is a ticketing system to be placed into a lobby group and then into a gameserver. Ethereal Engine has API call examples of this

Match User Relation

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-user/match-user.class.ts

Open Match Endpoint Reference

Match the ticket for an assignment

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket/match-ticket.class.ts

Match Gameserver Instance Relation

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-instance/match-instance.class.ts

Get a ticket for assignment to a gameserver instance

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket-assignment/match-ticket-assignment.class.ts

Agones Actions

unreal_bp_actions

Ethereal-Engine-Bridge-Unreal-Example

https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example

Preinstall Requirements

Add Plugins

Screenshot 2022-06-06 193750

Targeting support for 4.26 and 4.27

Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal

https://github.com/etherealengine/XRE-Bridge-Unreal/

This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine

https://api-dev.etherealengine.com/openapi/

This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!

This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database

Screen Shot 2022-06-04 at 4 25 43 PM

Blueprints multiplayer Unreal reference

https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/

Modeled after an updated version of

https://www.unrealengine.com/marketplace/en-US/product/multiplayer-shootout +https://docs.unrealengine.com/4.27/en-US/Basics/Projects/UIProjectConversion/

https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/BlueprintMultiplayer/

+ + + + \ No newline at end of file diff --git a/docs/creator/tutorials/index.html b/docs/creator/tutorials/index.html new file mode 100644 index 000000000000..479536834f10 --- /dev/null +++ b/docs/creator/tutorials/index.html @@ -0,0 +1,16 @@ + + + + + +Tutorials | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/guest/index.html b/docs/guest/index.html new file mode 100644 index 000000000000..6764880bd795 --- /dev/null +++ b/docs/guest/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal for Guests | etherealengine + + + + +
+

Ethereal for Guests

Whether you're a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine.

+ + + + \ No newline at end of file diff --git a/docs/host/Admin_Dashboard/index.html b/docs/host/Admin_Dashboard/index.html new file mode 100644 index 000000000000..b9bca96ecf51 --- /dev/null +++ b/docs/host/Admin_Dashboard/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal Engine Admin Panel Guide | etherealengine + + + + +
+

Ethereal Engine Admin Panel Guide

Dashboard

Usage Dashboard

Usage Time Series

Projects

Managing Projects

Project Table

Name

Version

Commit SHA

Commit Date

Update

GitHub Integration

User Access

Invalidate Cache

View Project Files

Routes

Location

Create Location

Name

Max Users

Scene

Type

Media Toggles

Make Lobby

Location Table

Instance

Patch InstanceServer

Instance Table

Instance Table Actions

Users

Create User

Name

Avatar

Scopes

Admin:Admin
Benchmarking:read/write
Bot:read/write
contentPacks:read/write
Editor:write
globalAvatars:read/write
Groups:read/write
Instance:read/write
Invite:read
Location:read/write
Party:read/write
Projects:read/write
realityPacks:read/write
Recording:read/write
Routes:read/write
Scene:read/write
Server:read/write
Settings:read/write
Static_resource:read/write
User:read/write

User Table

Invites

Avatar

Create Avatar

Avatar Name

File Source

Avatar Thumbnail

Avatar Table

Resources

Create Resource

Name

Project

File Source

Benchmarking

In work

Bots

In work

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/AWS_setup/index.html b/docs/host/devops_deployment/AWS_setup/index.html new file mode 100644 index 000000000000..e65ef563ae1f --- /dev/null +++ b/docs/host/devops_deployment/AWS_setup/index.html @@ -0,0 +1,341 @@ + + + + + +Ethereal Engine on AWS | etherealengine + + + + +
+

Ethereal Engine on AWS

The value RELEASE_NAME referenced throughout this guide is the name of the deployment, e.g. dev or prod.

Ways of serving client files in production

There are multiple ways to serve built client files in a production environment. +You should decide how you want to serve them now, because a few later steps will be affected +by that choice, and changing your AWS configuration after everything has been set up one way +is a little tricky:

  • From client pods (separate from API pods)
  • From API pods
  • From the storage provider, such as S3/Cloudfront

Serve client files from client pods

This is the default method. The Helm charts assume that the deployment will have client pods +to serve client files, and the client ingress will point traffic to the client pods. The client +URL will be pointed to the EKS Load Balancer, and you will not need a separate client certificate.

This option gives you slightly more flexibility in scaling a deployed cluster than serving +from the API pods, since you can scale the number of API and client pods independently.

Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture +of how projects are built and served, and serving from the Storage Provider may end up being the only +allowable option.

Serve client files from API pods

This will make your builder build and serve the client service from the API pods. The Helm +chart will not have a client deployment, serviceaccount, configmap, etc., and the client +ingress will point to the API pods. The client URL will be pointed to the EKS Load Balancer, +and you will not need a separate client certificate.

To enable this, set client.serveFromApi to true in your Helm config file when you are configuring it. +This needs to be applied to both the builder deployment and the main deployment, but if you set this +before deploying anything, it will be applied to both.

This option can save you some money by requiring fewer nodes in order to host all of the +API+client pods you desire, as you do not need capacity for separate client pods. It offers +slightly less flexibility in scaling since you cannot scale the number of API and client pods +separately; more client capacity would require more API capacity, and vice versa. It also +will result in slightly longer deployment times, as the combined API+client Docker images +are larger than an API-only or client-only image (though smaller than the sum of the two +separate images), which will mean a few more seconds to download to each node.

Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture +of how projects are built and served, and serving from the Storage Provider may end up being the only +allowable option.

Serve client files from Storage Provider (S3 + Cloudfront)

This will make the client build process push all of its built files to S3 and serve them via +Cloudfront. Static resources will also be served from the client domain instead of a separate +resources domain. The client URL will be pointed to the Cloudfront distribution, not the EKS Load +Balancer; only API and instanceserver traffic will go to the EKS cluster. You will need a separate +client certificate, but you will not need a resources domain certificate.

As of this writing, only Amazon S3/Cloudfront is supported as a storage provider +in a cloud environment.

To enable this, set builder.extraEnv.SERVE_CLIENT_FROM_STORAGE_PROVIDER to true in the +Helm config file when you are configuring it. Also make sure that builder.extraEnv.STORAGE_PROVIDER is set to s3.

This option can greatly speed up the time it takes for users to fully load your worlds, +since every client file can be served from a CDN close to them, rather than +having to fetch them all from the closest physical server. It will also slightly speed up build times and deployment +times since the client build does not need to be pushed to a Docker repo (though a cache of the build will still +be pushed to speed up future builds).

Create EKS cluster with four nodegroups

You first need to set up an EKS cluster for Ethereal Engine to run on. +While this can be done via AWS' web interface, the eksctl CLI +will automatically provision more of the services you need automatically, +and is thus recommended.

First, follow these instructions +for setting up aws-cli, eksctl, and configuring aws-cli with your AWS credentials. +You should also set up kubectl and Helm, as we will be using that to install multiple codebases from Charts.

Next run the following command:

eksctl create cluster --name <name> --version <version> --region <region> --managed --nodegroup-name <name> --node-type <instance type> --nodes <target_node_number> --nodes-min <minimum_node_number> --nodes-max <maximum_node_number> --spot

This will create an EKS cluster with a managed nodegroup in the specified region, including automatically +creating subnets, making a VPC, and more. It may take up to 15 minutes to complete.

You can also use the flag --zones <zone1>,<zone2> to specify which Availability Zones the cluster +should set up in. Some regions have zones that are unavailable, but which eksctl will try to +use if --zones is not specified, leading to the setup to fail. As an example, us-west-1 (as of this +writing) does not have any resources available in us-west-1b; if you are setting up in us-west-1, +you would want to use --zones us-west-1a,us-west-1c.

Note that the region matters for almost all services in AWS. The default region is 'us-east-1', +but if you make the cluster in any other region, you'll need to make sure you're creating certs, +DNS records, etc. in the same region.

As of this writing, the API and client are configured to run on a nodegroup named 'ng-1'. +If you name it something else, be sure to change the NodeAffinity in the configuration file. This is one of four +nodegroups that will be created for various services to run on.

Make sure to increase the maximum node limit, as by default target, minimum, and maximum are +set to 2, and Ethereal Engine's setup will definitely need more than two nodes if you've configured +them to use relatively small instance types such as t3a.medium.

Enable EBS CSI Addon (if EKS version is 1.23 or later)

Follow the instructions here +to enable an EKS addon that's required for any cluster that will have Persistent Volumes, which an +Ethereal Engine deployment cluster will.

Install Cluster Autoscaler (optional)

While not necessary, it can be useful to have an autoscaler installed in the cluster to increase +the number of nodes available for pods when the cluster has high traffic and to decrease that +number when it has low traffic.

Follow these instructions +to set up the autoscaler. Any managed nodegroups created in the following steps should by default be +tagged such that the autoscaler can control them, so no further action should be required.

Note that there is some lag time on scaling up and down. It generally takes about 5 minutes from +the time that the autoscaler sees the need to add more nodes before those nodes have been spun up, +the appropriate Docker image has been installed onto them, and they are ready to be used. It takes about +15 minutes for the autoscaler to actually remove nodes that are deemed superfluous, as a hedge against +the recent high traffic picking up again.

The OIDC provider that was created in the prior step, installing the EBS CSI Addon, can be re-used in this step.

Create launch template

Go to EC2 -> Launch Templates and make a new one. Name it something like 'etherealengine-production-instanceserver'. +Most settings can be left as-is, except for the following:

  • Storage -> Add a volume, set the size to ~20GB, and for Device name select '/dev/xvda'.
  • Network Interfaces -> Add one, and under 'Auto-assign public IP' select 'Enable'

Create nodegroup for instanceservers

Go to the AWS website, then go to EKS -> Clusters -> click on the cluster you just made -> Configuration -> Compute. +You should see one managed nodegroup already there; clicking on its name will open up information +and editing, though you can't change the instance type after it's been made.

Back at the Compute tab, click on Add Node Group. Pick a name (something like ng-instanceservers-1 is recommended), +select the IAM role that was created with the cluster (it should be something like eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>), +toggle the Use Launch Template toggle and select the launch template you made in the previous step, +then click Next. On the second page, Choose the instance type(s) you'd like for the group, +set the minimum/maximum/desired scaling sizes, and hit Next (t3(a).smalls are recommended). +There may be connection issues with instanceserver instances in private subnets, so remove all of the private +subnets from the list of subnets to use, and make sure that public subnets are being used (sometimes +the workflow only selects private subnets by default). Hit Next, review everything, and click Create.

Create nodegroup for redis

Redis should get its own nodegroup to isolate it from any other changes that might be made to your cluster. +As with the instanceserver nodegroup, it's not strictly necessary, but can prevent various other things from +going down due to the redis servers getting interrupted.

Back at the Compute tab, click on Add Node Group. Pick a name (the default config in ethereal-engine-ops assumes +a name of 'ng-redis-1'), select the IAM role that was created with the cluster +(it should be something like eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>), +toggle the Use Launch Template toggle and select the launch template used to make the initial nodegroup, +then click Next. On the second page, Choose the instance type(s) you'd like for the group, +set the minimum/maximum/desired scaling sizes (you can probably get away with a single t3(a).small, but it's recommended +to have at least two nodes so that one going down doesn't kill the entire deployment from a lack of redis), and hit Next. +The default subnets should be fine, so hit Next, review everything, and click Create.

Create nodegroup for builder

The full Ethereal Engine stack needs a builder server within the cluster in order to bundle and build +Ethereal Engine projects into the codebase that will be deployed. This should run on its own nodegroup +that has a single node - only one copy of the builder should ever be running at a time, and +due to the high memory needs of building the client service, a box with >8 GB of RAM is needed.

Back at the Compute tab, click on Add Node Group. Pick a name (something like ng-dev-builder-1 is recommended) and +select the IAM role that was created with the cluster (it should be something like +eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>). You don't need to use any Launch Template +for this nodegroup. Click Next.

On the second page, you can change the Capacity Type to Spot if you want to in order to save money; the builder +service will likely not be running very often or for too long, so the odds of it getting interrupted by Spot instance +outages are low, and it can always re-build if that does happen. Set the Disk Size to 50 GB; it takes a good deal of +disk space to install and build the Ethereal Engine codebase, and the default 20 GB will almost certainly not be enough.

For Instance Types, you need to only select types that have more than 8 GB; t3a.xlarge are the cheapest that fit +this criteria. If you were to pick something with 8GB, it's highly likely that most builds would crash the node, +as Kubernetes tends to restart nodes if they get anywhere near memory capacity. +Under Node Group Scaling Configuration, set all three nodes values to 1. We only want a single copy of the builder +at any given time, and running multiple powerful boxes can get pricey. Click Next.

You can leave the subnets on the next page alone and click Next. On the last page, click Create.

Create ECR repositories for built images.

The Ethereal Engine deployment process will be building multiple Docker images, and those need to be stored somewhere. +In AWS, that somewhere is Elastic Container Registry. +You need to make those repositories in the same AWS region where the EKS cluster is running.

Go to the ECR link above and click Get Started under Create a Repository. If you're very concerned about any of your +Ethereal Engine project codebase(s) getting out, you can choose Private for Visibility Settings, but normally Public is fine. +You'll be needing to create multiple repositories for each deployment, e.g. several repos for a dev deployment, +several more for a prod deployment, etc.

Assuming you're first doing a dev deployment, name the first repo etherealengine-<RELEASE_NAME>-builder under Repository +Name, e.g. etherealengine-dev-builder. You shouldn't need to change any other settings, though if you're using a Private +repo and want to turn on Tag Immutability, that's fine. The image tags that are generated should never collide, but it +will prevent any manual overwriting of a tag. Click Create Repository.

You will need to make four more repos for each of the services that are deployed as part of the Ethereal Engine stack - +api, client, instanceserver and taskserver, which are also in the form etherealengine-<RELEASE_NAME>-<service_name>. +e.g. etherealengine-dev-api, etherealengine-dev-client, etherealengine-dev-instanceserver and etherealengine-dev-taskserver. +Everything else can be left alone for those, too.

On the repositories page, you should see both of +the repositories you made. If you don't see any, you may be on the wrong tab up top - click Private or Public to switch +between them. Also check that you're in the right AWS region. You'll see a column 'URI'. If you made public repos, +the URIs should be in the form public.ecr.aws/<identifier>/etherealengine-<RELEASE_NAME>(-builder); if you made private +repos, the URIs should be in the form <AWS_account_id>.dkr.ecr.<AWS_region>.amazonaws.com/etherealengine-<deployment>(-builder). +Take note of everything before the /etherealengine-<RELEASE_NAME> - you'll need to add that as a variable in later steps. +It will be called ECR_URL there.

Create IAM Roles for S3/SES/SNS (or a single admin role)

Ethereal Engine interfaces with several AWS services and requires credentials for these purposes. You could make +one admin role with full access to all AWS services, but we recommend making separate, scoped roles for +each individual service. To create a role, do the following:

Creating an IAM role

Go to IAM->Users, and click on the Add User button. For User Name, enter <service>-admin, e.g. S3-admin. +Check the box for Programmatic Access, the click on the Next:Permissions button. +Click on 'Attach existing policies directly'. In the Filter Policies text box, you'll want to +enter the name of the service to narrow down the policy list significantly. Then, look for the FullAccess +policy for that service and select that, and click the Next:Tags button. You don't need to tag it with +anything, just click the Next:Review button, then the Create User button.

The following screen should show Success and have the user listed. Copy the 'Access key ID' somewhere, and +also click the Show toggle under 'Secret access key' and copy that elsewhere as well. You will put these +into the Helm config file later.

IAM Roles to create

Here are the services you want to create IAM admin users for, and the associated permissions you want to +grant them:

  • S3: AmazonS3FullAccess, CloudFrontFullAccess
  • SNS: AmazonSNSFullAccess

You'll also need to create an IAM user that GitHub Actions can use to access the cluster and push/pull +Docker images from ECR. By convention, we call this user 'EKSUser', and it needs these +permissions: AmazonEKSClusterPolicy, AmazonEKSWorkerNodePolicy, AmazonEKSServicePolicy, AmazonElasticContainerRegistryPublicFullAccess, AmazonEC2ContainerRegistryFullAccess

Creating new credentials for an IAM user

If you ever lose the secret to a user, or want to make new credentials for whatever reason, go to +IAM->Users and click on that user. Click on the 'Security credentials' tab, and under 'Access keys' you +should see a button 'Create access key' and, underneath that, 0-2 existing keys with some information +about them and an 'x' on the far right to delete it. If there are two keys for that user, you +must deactivate and delete one of them before making a new one.

Click the Create button, then make sure to save the public and secret keys somewhere and put them into +the Helm config file.

Create RDS box

Ethereal Engine is backed by a SQL server. We use MariaDB in development, but it has also been run on AWS with +Aurora without issue. Most other versions of SQL should work but have not been explicitly tested.

Accessing RDS box from an external machine

By default, an RDS box is only accessible from within the VPC it's located. +If you want to be able to connect to it from outside that VPC, you'll need to either set up a bastion box +and SSH into that box, or make the RDS box publicly accessible.

Setting up a bastion box is not covered here at this time. The steps to make it public will be noted +below by Make RDS public

Create RDS instance

Go to RDS and click the Create Database button. Most options can be left at their default values. +Under Settings, give a more descriptive DB cluster identifier. The Master Username can be left as admin; +enter a Master Password and then enter it again in Confirm Password.

Under DB instance class, pick an option that best meets your pricing needs.

Under Availability and Durability, it's recommended that you leave it on the default of +making an Aurora Replica in another AZ.

Under Connectivity, make sure that it's in the VPC that was made as part of the EKS cluster.

Make RDS public +If you want to be able to access it externally, you should set Public Access to 'Yes'.

Under VPC security group, select the ones titled +eksctl-<EKS_cluster_name>-cluster-ClusterSharedNodeSecurityGroup-<random_string> and +eks-clustersg-<EKS_cluster_name>-<random_string>.

Open the top-level Additional Configuration dropdown (not the one within Connectivity). Under Database Options-> Initial Database Name, +name the default database and save this for later use in the Helm config file.

Finally, click the Create Database button at the very bottom of the page.

Make RDS Public You will need to add a Security Group to the RDS instance that allows traffic over port +3306 (or whatever port you chose to run it on). You can have this SG only let in traffic from your IP address(es) +if you want to be very secure about this, or from anywhere (0.0.0.0/0) if you're less concerned about someone +getting access.

Some values to note for dev/prod.template.values.yaml: +sql.database will be what you entered for Initial Database Name +sql.user and sql.password will be the name and password of the admin user +sql.host will be the Endpoint of the RDS instance/cluster; find this by going to RDS -> Databases, +clicking on either the lone DB identifier (if made in a single AZ) or the top-level regional cluster +identifier (if set up in a multi-AZ deployment); the look for Endpoint (single-AZ) or, if multi-AZ, +the Endpoint name that has type 'Writer instance'.

Edit security group to allow instanceserver traffic into VPC

You'll need to edit the new cluster's main security group to allow instanceserver traffic. +On the AWS web client, go to EC2 -> Security Groups. There should be three SGs that have +the node's name somewhere in their name; look for the one that is in the form +eks-cluster-sg-<cluster_name>-<random_numbers>. It should NOT end with /ControlPlaneSecurityGroup +or /ClusterSharedNodeSecurityGroup. +Click on that, then the Inbound Rules tab, then click Edit Inbound Rules.

You'll need to add two rule sets:

  • Type: Custom UDP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')
  • Type: Custom TCP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')

Create Route 53 Hosted Zone and set up ACM certificates

Before installing Nginx to the cluster, you'll need to have all of the networking squared away. +This requires creating the necessary SSL certificates and creating some DNS records to point +various subdomains to the right place.

Purchase and register domain through Route53 (optional)

If you do not have a domain for your application already, it's easiest to register it through Route53. +Go to Route53->Domains->Registered domains, then click the 'Register Domain' button, and follow the +workflow to register a domain name.

Create Route 53 Hosted Zone

In the AWS web client, go to Route 53. Make a hosted zone for the domain you plan to use for +your setup of Ethereal Engine. You'll be coming back here later to create DNS records.

Open the Hosted zone, then click on 'Hosted zone details' to see more information. The value 'Hosted zone id' +is used in the dev/prod.values.yaml file for 'ROUTE53_HOSTED_ZONE_ID'

Point external registrar subdomains to use Route53 Nameservers (only if your domain is registered outside Route53)

If you already have a domain registered with another registrar service, you'll need to add some DNS records +in there to point the specific subdomains you'll be using to AWS' nameservers.

First, go to Route53->Hosted Zones and open the domain you'll be using by clicking on the domain name (or +highlighting the row and clicking the 'View details' button). There should be two records under Records. +Look for the one of type 'NS'; under 'Value/Route traffic to', there should be four lines that all start +with 'ns-'. These will be used shortly.

Go to your external registrar and go to the DNS records page. For each subdomain that will be in use, you +need to add four records of type 'NS'. The Name wil be the subdomain, and the Nameserver will be one of +the four lines under the 'NS'. You need a record for each of the four lines.

If you're setting up multiple deployments, e.g. both a dev and prod deployment, you'll need a set of four +NS records for each subdomain that those deployments will be behind.

Create certificates with ACM

Go to Amazon Certificate Manager. If there are no certs in that region, click on Get Started under Provision Certificates, +otherwise click on Request a Certificate.

You should select Request a Public Certificate, then select Request a Certificate. The next page +should be headed Add Domain Names. You should add both the top-level domain, such as etherealengine.org, +as well as a wildcard for all subdomains e.g. *.etherealengine.org, then click Next.

Choose DNS Validation on the next page and click Next. You can skip adding tags and just click Review, +then Confirm on the final page.

You should be sent to a page headed Validation. Click on the arrow next to each domain to open more +options. Click on the button Create Record in Route 53 to open a confirmation modal, and in that modal +click Create.

As it indicates, it can take up to 30 minutes for these domains to be validated. If you click on Complete +after triggering the record creation for each of them, you should be sent back to the Certificates page. +Opening the cert you just made will show the validation status of each domain.

If you open the details of this certificate, there should be a field 'ARN' with a value that looks +something like arn:aws:acm:<region>:<AWS account ID>:certificate/<a UUID>. Take note of this for later, +when you go to install ingress-nginx.

If you are serving client files from client or API pods

You should follow the above instructions to make a second certificate for resources.<domain>. +Note that this certificate MUST be made in us-east-1, regardless of which region everything else is +set up in; as of this writing, CloudFront can only use certificates in us-east-1.

If you are serving client files from the Storage Provider

You should follow the above instructions to make a second certificate for <RELEASE_NAME>.<domain>. +Note that this certificate MUST be made in us-east-1, regardless of which region everything else is +set up in; as of this writing, CloudFront can only use certificates in us-east-1.

Install Agones, ingress-nginx, and a copy of redis for each deployment

Now that the cluster is up and running, we can install everything onto it. +When you created the cluster with eksctl, it should have created a context pointing to +it in kubectl. Run kubectl config get-contexts to get all of the contexts it knows about; +the one with a star next to it should be named <your_AWS_username>@<cluster_name>. +If that isn't present, you'll have to edit the configuration to make the appropriate context.

You next need to add the Agones, ingress-nginx, and redis Helm charts to helm by running +helm repo add agones https://agones.dev/chart/stable, helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx, and helm repo add redis https://charts.bitnami.com/bitnami. +You should also at this time add Ethereal Engine's repo via helm repo add etherealengine https://helm.etherealengine.org.

If you ever suspect that a chart is out-of-date, run helm repo update to update all of them to the latest.

Install Agones

From the top level of this repo, run helm install -f </path/to/agones-default-values.yaml> agones agones/agones. +This says to install a service called 'agones' from the 'agones' package in the 'agones' chart, and to configure it with +agones-default-values.yaml that can be found in ethereal-engine-ops repo.

Install redis for each deployment

Each deployment of Ethereal Engine uses a redis cluster for coordinating the 'feathers-sync' library. +Each redis deployment needs to be named the same as the deployment that will use it; for an +Ethereal Engine deployment named 'dev', the corresponding redis deployment would need to be named +'dev-redis'.

Run helm install -f </path/to/redis-values.yaml> <RELEASE_NAME>-redis redis/redis to install, e.g. +helm install -f </path/to/redis-values.yaml> dev-redis redis/redis.

redis-values.yaml can be found in ethereal-engine-ops repo.

If you named the redis nodegroup something other than 'ng-redis-1', you'll have to alter the value in +redis-values.yaml in two places to your redis nodegroup name. +If you didn't create a nodegroup just for redis, you must omit the -f </path/to/redis-values.yaml>, +as that config makes redis pods run on a specific nodegroup.

Redis can be installed as part of the Ethereal Engine chart so long as the config file for the Ethereal Engine installation has 'redis.enabled' set to true. +In that case, you should skip the above step of installing redis separately. This is not recommended for production +environments, though, since upgrades to an Ethereal Engine installation will usually reboot the redis servers, +leading all of the instanceservers to crash due to their redis connections being severed.

This breaks Agones' normal behavior of keeping Allocated instanceservers running until every user has left and slowly replacing +old Ready instanceservers with new ones, maintaining an active pool of instanceservers at all times. You will encounter a period +of time where there are no active instanceservers at all, which is not recommended, and all instanceservers in use +will immediately go down.

Install ingress-nginx

This step cannot finish until the associated ACM Certificate is fully validated +Open local version of nginx-ingress-aws-values.yml file. Take note of the line +service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "<ACM Certificate ARN for SSL>" +Replace the bit in angle brackets, including the angle brackets, with the ARN of the certificate +you made for the top-level domain and all wildcarded subdomains, e.g. +service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-1:103947711118:certificate/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"

Do not commit this file with the ARN inserted; once you've completed this step, revert the file back +to the state it was committed in.

From the top level of this repo, run helm install -f </path/to/nginx-ingress-aws-values.yml> nginx ingress-nginx/ingress-nginx +This says to install a service called 'nginx' from the 'ingress-nginx' package in the 'ingress-nginx' chart, and to configure it with +a file found at nginx-ingress-aws-values.yml.

Set up Simple Email Service (optional)

If you want to enable email magiclink login, you will need to set up Simple Email Service (SES).

In the AWS web client, go to SES -> Configuration -> Verified Identities. Click Create Identity, then under 'Identity type' +select 'Domain'. Enter the top-level domain under the 'Domain' field. Finally, click the 'Create identity' button.

Create SMTP credentials

You need to create SMTP credentials in order to authorize SES. These will show up as an IAM user, +but you must go through an SES-specific process to get valid credentials; just creating an IAM user +with SESFullAccess will not work.

Go to an SES page and select 'SMTP Settings', then click the button 'Create SMTP Credentials'. +You can leave the default IAM User Name as-is; click the Create button. You should be taken to a screen +says a user has been created successfully. Click on 'Show User SMTP Security Credentials'.

You will see a Username and Password. These credentials will go into the Helm config file, under +AWS_SMTP_USER and AWS_SMTP_PASS, respectively. You must also fill in the region that you've created these credentials +in, replacing <SES_REGION> in api.extraEnv.SMTP_HOST.

Move SES out of Sandbox

By default, SES domains are in Sandbox mode, where they can only send emails to verified email addresses. +To request that the domain be moved out of Sandbox mode, go to SES->Email Sending->Sending Statistics. +Click on the button 'Edit your account details' to open the modal. Set 'Enable Production Access' to Yes, +leave Mail type on 'Transactional', then fill in the Website URL, add a Use case description (basically +just assure them that this is for account login only, not anything else), click the checkbox to agree +to their TOD, and click the button 'Submit for review'.

It may take up to a few days for them to take action. If the request is rejected, address their concerns. +Once you have been approved, email login should work for any email address.

Verifying test emails

Before you have production use for your SES domain, in order to log in you'll have to verify specific email +addresses with SES. Go to SES->Identity Management->Email Addresses. Click on the button 'Verify a New Email +Address'. Enter the address you want to test with, then click 'Verify This Email Address'. You should soon +receive an email with a link to verify it (it may go to your Spam folder). Once you've followed the link, +you can log in with that address.

Set up Simple Notification Service (optional)

If you want to enable text message-based magiclink login, you will need to set up Simple Notification Service (SNS).

In the AWS web client, go to SNS -> Topics and Create a new topic. +Give it a name, and selected 'Standard' as the type, then click Create Topic.

Set up S3 bucket for static resources and Cloudfront distribution

Various static files are stored in S3 behind a Cloudfront distribution. If you are serving the client files +from the Storage Provider, then all client files will be stored and served from these as well.

Create S3 bucket

In the AWS web client, go to S3 -> Buckets and click Create Bucket. +Name the bucket <name>-static-resources, e.g. etherealengine-static-resources, and have it be in Region us-east-1. +Under Object Ownership, select 'ACLs enabled', and under that select 'Object Writer'. +Under Block Public Access Settings For The Bucket, uncheck the checkbox Block all Public Access; +you need the bucket to be publicly accessible. +Check the box that pops up confirming that you know the contents are public. +All other settings can be left to their default values; click Create Bucket.

Open the bucket's settings and go the Permissions tab. Midway down is 'Access control list'. Edit that, and +Check the boxes for Objects:List and Bucket ACL:Read for 'Everyone (public access)'. Click the box with the +warning label that appears that says "I understand the effects of these changes on my objects and buckets", +then click Save Changes. +At the bottom of the Permissions tab is a Cross-origin Resource Sharing (CORS) box. +It should have the following settings; if not, click Edit and copy this in:

[
{
"AllowedHeaders": [],
"AllowedMethods": [
"HEAD",
"GET",
"POST"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]

Create Cloudfront distribution

In the AWS web client, go to Cloudfront -> Distributions and click on Create Distribution. +Under 'Web', click on Get Started.

Under Origin, click on the text box under Origin domain, and select the name of the S3 bucket you just made. +The Name field should be automatically populated, and should be left as whatever that value is.

Several fields in Default cache behavior will be changed.

Under Viewer -> Viewer protocol policy, select 'Redirect HTTP to HTTPS' +Under Viewer -> Allowed HTTP methods, select 'GET, HEAD, OPTIONS', and check Cache HTTP methods -> OPTIONS.

In Cache key and origin requests, leave it on Cache policy and origin request policy. +If this option is not available, see the below subsection for Legacy cache settings

For Cache policy, you will need to make a new policy, which is easily done by clicking the link Create policy +underneath the selector; this will open a new tab. Name this policy anything you want, e.g. 'Cached-on-headers', +then under Cache key settings, click on the Headers selector and select 'Include the following headers'. A new +selector should appear under that titled Add header. Click the selector, and check 'Origin', +'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away from the menu. Click the 'Create' +button to create the new policy.

Once the policy has been created, go back to the tab that you were creating the CloudFront distribution in. +Click the refresh button to the right of the Cache policy selector to fetch your new policy, then click the selector, +and your new policy should appear in the selector at the bottom of the list under the header 'Custom'. Select it.

For Origin request policy, select the option 'CORS-S3Origin'.

You should also make a custom response header policy so that files are served with the Origin-Agent-Cluster +header, which will tell most browsers to isolate resources for same-site cross-origin requests. To do that, +you will need to make a custom response header policy. Under Response headers policy, select Create Policy. +This will open a separate tab. Name this something like Origin-Agent-Cluster, then under Custom headers, +click Add header. For name, enter Origin-Agent-Cluster, and for Value, enter ?1. Then click the Create +button at the bottom.

Go back to the tab where you were creating the Cloudfront distribution. Click the refresh button to the right of +the Response headers policy selector to fetch the new policy, then click the selector, and your new policy should +appear in the selector at the bottom of the list under the header Custom. Select it.

Under Settings, you can change Price class to 'Use Only North America and Europe' to save some money. +For Alternate Domain Names, click 'Add item', then in the text box that appears, enter 'resources.<domain>', e.g. +resources.etherealengine.org, or '<RELEASE_NAME>.<domain>', e.g. dev.etherealengine.org, depending on +whether you are serving the client files from client/API pods or the Storage Provider, respectively. +Under Custom SSL Certificate, click on the selector that says 'Choose certificate', then select the +'resources.<domain>'/'<RELEASE_NAME>.<domain>' certificate you made earlier. If you are serving the client +files from the Storage Provider, under Default root object, enter client/index.html; if you are serving +the client files from client/API pods, leave this blank.

Everything else can be left at the default values, click Create Distribution.

Legacy cache settings

If for some reason Cache policy and origin request policy is not available for you, and you have to use +Legacy cache settings, the under Headers, select 'Include the following headers'. Under Add header that appears, +click on the selector titled 'Select headers', and in the menu that opens, check 'Host', 'Origin', +'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away.

Set up DNS records

The Nginx Load Balancer must be fully set up and running before this step can be completed

In the AWS web client, go to Route 53, then go into the Hosted Zone you made earlier. +Click on Create Record. If it starts you under Quick Create Record, click the link +'Switch to Wizard'; it's not necessary, but the wizard is handy.

Under Routing Policy, leave it on Simple Routing and click Next. Then click Define Simple Record.

The first record should be for the top-level domain, e.g. etherealengine.org, so leave the Record Name +text field blank. Under Value/Route Traffic To, click on the dropdown and select +Alias to Network Load Balancer. Select the region that your cluster is in. +Where it says Choose Load Balancer, click the dropdown, and select the NLB that was created. +Leave the Record Type as 'A - Route traffic to an IPv4 address and some AWS resources', then click +Define Simple Record.

You can keep clicking Define Simple Record to make more records in one batch. When you're +done, click Create Records.

You should make the following 'A' records to the loadbalancer, substituting your domain for 'etherealengine.org':

  • etherealengine.org
  • *.etherealengine.org
  • @.etherealengine.org
  • api-dev.etherealengine.org
  • api.etherealengine.org
  • dev.etherealengine.org -- Only if serving client files from client/API pods
  • instanceserver.etherealengine.org
  • instanceserver-dev.etherealengine.org

You also need to make an 'A' record pointing 'resources.etherealengine.org' or '<RELEASE_NAME>.etheralengine.org' to the +CloudFront distribution you made earlier. +Instead of 'Alias to Network Load Balancer', select 'Alias to Cloudfront distribution', then click the text box that appears +that says 'Choose distribution'. A selector should appear with the subdomain you're routing as well as the Cloudfront +distribution's domain name, which you should click on. Then click Define simple record.

Create GitHub fork of Ethereal Engine repository.

The Ethereal Engine codebase is most easily deployed by forking it and configuring some Secrets so that the included GitHub +Actions can run the deployment for you. You can run all of the commands that the <dev/prod>-deploy action runs manually +if you so choose, and in that case, you don't need to fork the GH repo.

Go to https://github.com/etherealengine/etherealengine. In the upper right-hand corner, there's a button 'Fork'. Click that, +then click the account/organization you wish to fork it to. You should be taken to your fork in a short time.

You'll need to set several Secrets (runtime variables) for GitHub Actions. By default GitHub Actions should be fully +enabled, but you can double-check by going to Settings->Actions. Allow All Actions should be selected under Actions +Permissions.

Next click on Secrets under Settings. There should be none by default. Click on New Repository Secret near the top of +this page to make a new one. You will need to make several Secrets with the following Names and Values:

  • EKS_AWS_ACCESS_KEY -> The public Key of the EKSUser IAM user
  • AWS_REGION -> The region of your ECR repos and EKS cluster
  • EKS_AWS_SECRET -> The secret key of the EKSUser IAM user
  • CLUSTER_NAME -> The name of the EKS cluster
  • DEPLOYMENTS_ENABLED -> Set to true
  • DEV_REPO_NAME -> The base name of the dev ECR repository, e.g. etherealengine-dev (all references to the builder and service repos will append -builder/-<service> to this value)
  • DOCKER_LABEL -> This can be almost anything, but you can use lagunalabs/etherealengine
  • ECR_URL -> The root ECR_URL for your repos, i.e. everything before the /etherealengine-dev-builder, e.g. 11111111111.dkr.ecr.us-west-1.amazonaws.com or public.ecr.aws/a1b2c3d4
  • PRIVATE_ECR -> Set this to true if your ECR repos are private, if they're public you don't need to set this at all

If you go to the Actions Tab, you might see a few workflow runs with green checkmarks. If so, you'll be re-running the +dev-deploy workflow shortly; its initial run just ran a check to see if it should do a deployment based on +DEPLOYMENTS_ENABLED, and since that wasn't set to true, it didn't do anything else. Now that that's set to true, +re-running it will trigger a deployment.

If you're asked to enable actions when going to the tab, and there are no runs listed after enabling actions, then you'll have to +trigger the workflow by pushing new code to the dev branch.

Grant EKSUser access to cluster

By default, only the IAM user who set up an EKS cluster may access it. +In order to let other users access the cluster, you must apply an aws-auth configmap to the cluster +granting access to specific IAM users. A template of aws-auth-template.yml file can be found in ethereal-engine-ops repo.

You'll need to provide a few values for this file. To find <rolearn>, in AWS go to EKS->Clusters-> +<your cluster>->Compute->Select a nodegroup. In the details should be 'Node IAM Role ARN'; copy this +and replace <rolearn> in the aws-auth file. <account_id> is the ID of your AWS account; in the upper +right corner of the AWS client should be <your_username>@<abcd-1234-efgh>. The 12-character string +after the @ is the account ID. Make sure to remove the -'s from the account ID when pasting it in. +<IAM_username> is the username of the IAM user you want to give access, e.g. EKSUser.

You can add multiple users by copying the - groups: section under mapUsers, e.g.

  mapUsers: |
- groups:
- system:masters
userarn: arn:aws:iam::abcd1234efgh:user/EKSUser
username: EKSUser
- groups:
- system:masters
userarn: arn:aws:iam::acbd1234efgh:user/FSmith
username: FSmith

When the aws-auth config file is filled in, just run kubectl apply -f path/to/aws-auth.yml.

Deploy to EKS using Helm

With all of the networking set up, you can finally deploy the codebase to EKS. +There's a couple of steps to this, which will involve deploying things with most but not all of the needed +configuration values, and then letting the deployment process fill in the rest.

Fill in Helm config file with variables

Template Helm config files for dev and prod deployments can be found in configs <dev/prod>.template.values.yaml. +Before filling them in, make a copy elsewhere, call that '<dev/prod>.values.yaml', and edit that copy. +Both the builder and main deployments should use the same config file. When the builder seeds the database, +it needs a number of values that only need to be configured for the other services, so all of the values +need to be defined in one config file.

There are many fields to fill in, most marked with <>. Not all are necessary for all situations - if you're not +using social login, for instance, you don't need credentials for Github/Google/Facebook/etc.

Configuration variables of note

Here are some configuration variables that you'll probably need to change based on your specific setup

<api/instanceserver/taskserver>.extraEnv.AUTH_SECRET

This is a secret value that is used to sign the JWTs that authenticate users. +You can use any string for this value, and a randomly-generated one of sufficient length, +i.e. 32 or more characters, will suffice. If this is changed after some users have signed +in, their login credentials won't work any more.

<api/client/taskserver>.affinity.nodeAffinity

Within the sections of the config for the api, client, instanceserver, etc., is a section that looks +something like this:

  affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- ng-1

The value, ng-1 in this example, must be changed to match whatever the name of the nodegroup that +that service will be running on, e.g. if you create a nodegroup for the instanceservers called +abcd-instanceservers-5, then you'd use that value under values:

If your EKS setup created a nodegroup for you, and you want to use that for the api, client, and +task servers, make sure to change the affinity value for them to whatever EKS named the +initial nodegroup.

builder.extraEnv.PRIVATE_ECR

If you're using a private ECR repo, set this to "true" in the builder config file.

(everything).image.repository

You'll need to replace every <repository_name> with the full ECR_URL of your non-builder repos, e.g. abcd1234efgh.dkr.ecr.us-west-1.amazonaws.com/etherealengine-dev-api. +Each service has to have the proper -<service> suffix on it, e.g. -api, -client, etc.

GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET

If you plan to backup Projects you create in the editor to GitHub, or install project from GitHub, it is necessary +to set up the OAuth app that will facilitate this before the initial installation. +See this document for +more information, and enter the appropriate ID/secret in these variables.

Run Helm install

Run helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME>-builder etherealengine/etherealengine-builder +and then run helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME> etherealengine/etherealengine

This will spin up the main and builder deployments using the Helm config file, <dev/prod>.values.yaml. +Neither will fully work yet, since there's no valid image in the repos yet. The GitHub +Actions and builder processes will make those images and update the deployments with the tags of the images they've built +so that they can pull down and use those images.

Kick off GitHub Actions

In GitHub, if you go to back to the Actions tab, you should see a dev-deploy action. Click on it, and you should see +a page showing its status, which should be all green checkmarks or indicators that things didn't run. In the upper +right, click Re-run all jobs. This will start it again, and now that DEPLOYMENTS_ENABLED is set to true, it should +attempt to build and deploy the builder.

(If actions were disabled at first, you'll have to merge additional code into the dev branch to get it to start the dev-deploy process)

Overview of the build process

The full build and deployment process works like this:

  1. GitHub Actions builds just enough of the Ethereal Engine monorepo to fetch any installed Ethereal Engine projects.
  2. GitHub Actions pushes this builder Docker image to the repo etherealengine-<release>-builder in ECR
  3. GitHub Actions updates the builder deployment to point to the builder image it just created.
  4. The builder deployment spins up the builder Docker image on its single node
  5. The builder connects to the deployment's database and checks if there is a table user. This is a proxy +for the database being seeded; if it does not exist, it seeds the database with the basic Ethereal Engine schema, +seeds the default project into the database and storage provider, and seeds various types.
  6. The builder downloads any Ethereal Engine projects that the deployment has added.
  7. The builder builds the Docker image for each service concurrently using these projects, building them into the client files as well as copying them so that the api and instanceservers have access to them. +If serving client files from the Storage Provider, the client files will be pushed to S3
  8. The builder pushes these final Docker images to the repos etherealengine-<release>-<service> in ECR (not the client image if serving client files from the Storage Provider)
  9. The builder caches all of the layers of each Docker file in S3 for faster build times on subsequent builds
  10. The builder updates the main deployment to point to the final images it just created.
  11. The main deployment spins up the final Docker images for the api, client (optional), instanceserver and taskserver services.

Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana +Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update config file(values.yml) for Xr env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

Upgrading an existing Helm deployment

One of the features of Helm is being able to easily upgrade deployments with new values. The command to +do this is very similar to the install command:

helm upgrade --reuse-values -f </path/to/*.values.yaml> --set api.image.tag=<latest_github_commit_SHA>,client.image.tag=<latest_github_commit_SHA>,instanceserver.image.tag=<latest_github_commit_SHA> <RELEASE_NAME> etherealengine/etherealengine

--reuse-values says to carry over all configuration values from the previous deployment. This is most important +for tags, since they're usually set inline with the helm install/upgrade command, not a Helm config. +Using -f <config_file> and --set <variables> after it will apply any changes on top of the +carryover values.

If you're not deploying a new build of the codebase, you can skip the entirety of the --set *.image.tag=<SHA>.

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/database_migrations/index.html b/docs/host/devops_deployment/database_migrations/index.html new file mode 100644 index 000000000000..98f08949ad36 --- /dev/null +++ b/docs/host/devops_deployment/database_migrations/index.html @@ -0,0 +1,16 @@ + + + + + +Database Migrations | etherealengine + + + + +
+

Database Migrations

Create Migration File

  1. In your ethereal engine repo run following command
  cd packages/server-core
  1. Afterward run following command to generate migration file: TIMESTAMP_NAME.ts i.e. 20230418102549_eks-column.ts in server-core folder.
  npm run migrate:make -- {NAME}

i.e.

  npm run migrate:make -- eks-column
  1. Move the migration file to your service's migrations folder. i.e. packages/server-core/src/setting/aws-setting/migrations
  2. Update that file with code to match your needs.

OpenAPI

Our server is set up with Swagger documentation to automatically generate from most endpoints. A few custom routes are not documented at this time, but most of the basic stuff is.

You can see the docs for a running Ethereal Engine instance locally at:

https://localhost:3030/openapi

Or on our dev cluster

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/docker_desktop/index.html b/docs/host/devops_deployment/docker_desktop/index.html new file mode 100644 index 000000000000..6803dc65a8f3 --- /dev/null +++ b/docs/host/devops_deployment/docker_desktop/index.html @@ -0,0 +1,49 @@ + + + + + +Ethereal Engine on Docker Desktop | etherealengine + + + + +
+

Ethereal Engine on Docker Desktop

NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.

Install kubectl, Helm, and Docker Desktop

If kubectl, Helm, +and/or Docker Desktop +aren't already installed on your machine, install them. Windows and Mac Docker Desktop installation instructions +can be found here and here.

You may also need to install Docker Compose

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local +services, you'll need to get the Ethereal Engine repo on your machine. This is most easily +done by running git clone https://github.com/etherealengine/etherealengine.git

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_minikube.sh.

Enable Kubernetes in Docker Desktop

Inside Docker Desktop, go to Settings. There should be a section for Kubernetes (as of this writing, located +between Docker Engine and Software updates settings). Click on that, then check the checkbox for Enable Kuberentes, +and then click the button Apply and restart. When Docker Desktop restarts, it should now run a minikube-like Kubernetes +cluster on startup. The Kubernetes context for this should be named docker-desktop.

Edit system hostfile to point EtherealEngine addresses to 127.0.0.1

You'll need to edit your hostfile to point certain domains to 127.0.0.1, which is how Docker Desktop routes traffic +to its Kubernetes cluster. On Linux, this is done by running sudo gedit /etc/hosts.

Add the following line:

127.0.0.1  local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org

You should also see a section that looks like this:

# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

The first line says to point several *-local.etherealengine.org domains internally to the Kubernetes cluster, +where the nginx ingress server will redirect the traffic to the appropriate pod. +The section it automatically added is used for giving Docker containers, including the Kubernetes cluster, +access to the host machine.

Make sure to save this file after you've edited it. On Linux, at least, you need root permissions +to edit it.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at docker-desktop by running kubectl config current-context, +which should say 'docker-desktop'. You can also run kubectl config get-contexts to get all contexts +that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to docker-desktop, from the top of the Ethereal Engine repo, run +helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones +and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in docker-desktop. After a minute or so, +all of these pods should be in the Running state.

Run build_docker_desktop.sh

When docker desktop's Kubernetes cluster is running, run the following command from the root of the Ethereal Engine repo:

./scripts/build_docker_desktop.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

The script builds the full-repo Docker image using several build arguments. Vite, which builds +the client files, uses some information from the MariaDB database created for local K8s deployments +to fill in some variables, and needs database credentials. The script will supply default values +for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, +VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your Docker Desktop K8s deployment +accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different +domain, then you'll have to set those three environment variables to what you want them to be (and also +change the hostfile records you made pointing those subdomains to 127.0.0.1)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for +different services, it will only run the parts needed for that service. This may take up to 15 minutes, +though later builds should take less time as things are cached.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained a couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. It's mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Run the following command: helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine.

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api +servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers +(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run +helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. +The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/index.html b/docs/host/devops_deployment/index.html new file mode 100644 index 000000000000..505a2092028a --- /dev/null +++ b/docs/host/devops_deployment/index.html @@ -0,0 +1,16 @@ + + + + + +Deployment | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/installing_projects/index.html b/docs/host/devops_deployment/installing_projects/index.html new file mode 100644 index 000000000000..d2b740f51518 --- /dev/null +++ b/docs/host/devops_deployment/installing_projects/index.html @@ -0,0 +1,75 @@ + + + + + +Installing Projects | etherealengine + + + + +
+

Installing Projects

Local Install Flow

To install a project locally, clone the repository you wish to install to the +/packages/projects/projects/ folder. You can do this with the follow commands:

cd packages/projects/projects/
git clone https://github.com/myorg/myrepo
cd myrepo
code .

This will create a folder name myrepo which must contain an xrengine.config.ts +file, and open the project in a new vscode window (such that git commands can be +handled by the new window). All you need to do now to run this project is re-run +the stack (with npm run dev).

Graphical Install Flow

Projects can also be installed and managed from the /admin/projects route. You must be +an admin and must have a linked GitHub account, which can be attained by having your +GitHub account linked to your Ethereal Engine account by signing in via GitHub. +(You do not need to have most recently signed in via GitHub, you just have to have +linked your GH account at some point)

See the section 'How to set up GitHub to install external projects' +for instructions on creating an OAuth app from GitHub, installing it into an Ethereal Engine deployment, +and authorizing it to have access to your GitHub organizations.

Click the 'Add Project' button:

You will see text fields for entering the source and destination repositories. +When you click away from the text fields, the URL will be checked both for the +repository existing, and for whether you have sufficient permission to access +that repository - read permission for the source repo (public repositories are +always available), and write or admin permission for the destination repo. If +you have never logged into GitHub with your current account, you will not be +allowed to add or update projects.

For the source repository, after entering the URL, you will also need to select +a branch to pull from. Your options are either the main branch for that repository, +or a branch that matches the RELEASE_NAME of the deployment, e.g. dev-deployment for +a deployment with the environment variable RELEASE_NAME=dev. If RELEASE_NAME is not defined, then +local is used; this could lead to multiple local installations of the platform conflicting, +but one can set RELEASE_NAME locally to something else in your .env.local file.

After the branch is selected, you also need to select a tagged commit from that branch, +or the most recent commit. As of this writing, you must manually tag project commits yourself, +though tags are copied over from the source repository when installing or updating a project.

The backend checks that the source and destination repos have the same project. +The project name is the name field in the project's package.json file. +If the destination repo's <RELEASE_NAME>-deployment branch is empty or nonexistent, then +any project can be uploaded to it. If the destination deployment branch is not empty, +then it can only be updated with different versions of that project. For example, +if the destination branch has project example1 in it, you will not be allowed to +overwrite it with a project test3, only other projects named example1.

You can only install a project with a given name once, and names are case-insensitive; +example1 is seen as the same name as ExamplE1. You would need to remove an existing project +in order to install a different project that has the same name, or rename one of the projects.

When everything is valid, you will be able to click the Submit button, which will install +the project.

Adding a project through this interface runs git clone in the background, same as above, +but will then upload all of the repository's files to the storage provider. These files will then be +downloaded and installed to the deployment's file system each time the docker builder +pod runs. This allows full version controlled access for local development flow +and version locking for production deployment. The source project code will then be force-pushed +to the branch <RELEASE_NAME>-deployment, so make sure that there is no work in that branch +that might get overwritten, and make a backup in another branch you do want to save it.

The Push to GitHub button will push the current code for that project to the <RELEASE_NAME>-deployment +branch if possible; it will never push to the main branch. If there are merge conflicts, it will instead +make a Pull Request on that branch with the changes; it will NOT force-push anything to this branch, +unlike adding or updating a project.

The Update button opens the same drawer as adding a new project, just with the destination repository locked in. +Assuming everything matches, it will also force-push to the <RELEASE_NAME>-deployment branch in the destination +repository.

The GitHub Repo Link button also opens this drawer, but you can only select the destination repository, not +the source repository, and no code is pushed anywhere.

The remove button will remove the folder containing that project. This will not delete the deployment +branch. WARNING: Any uncommitted & unpushed files will be lost.

Updating the Engine Version and Rebuilding Projects

Making changes to a project is not always reflected immediately in the running code. As of this writing, +project code is built into the client-side and backend files, and changes to project code require that +the codebase be updated. Locally, this just requires you to stop and restart the npm run dev command. +In a production environment, this requires that the builder process be restarted, so that it can +rebuild the client and backend code with the new project code.

Changes to scenes in projects do not require a rebuild - since they are stored external to the codebase +in the storage provider, and are downloaded anew by a client each time the scene is loaded, changes to +scenes will always be immediately available. The act of saving a project will clear any cached version +of the scene's static files, so the client will get the new version.

Additionally, if you want to update the core Ethereal Engine code, you will also need to re-run the builder +process with the new version of the code.

In a production environment, click on the button Update Engine/Rebuild. A drawer will open with +a selector for the engine version you want to update with. This will be an image in the builder's +linked image repository.

After selecting an engine version, if you click Submit now, you will just rebuild with the +newly-selected version of the main codebase, plus whatever versions of your projects are currently +in your linked repositories.

If you click on Update projects, +you can select the source commits for any installed projects that have a destination repo, same as with +the Add/Update project drawer. The projects will be updated before the builder is restarted.

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/managing_remote_kubernetes/index.html b/docs/host/devops_deployment/managing_remote_kubernetes/index.html new file mode 100644 index 000000000000..be36c55c8cbd --- /dev/null +++ b/docs/host/devops_deployment/managing_remote_kubernetes/index.html @@ -0,0 +1,18 @@ + + + + + +Cluster Management | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/microk8s_linux/index.html b/docs/host/devops_deployment/microk8s_linux/index.html new file mode 100644 index 000000000000..fe0304c3752b --- /dev/null +++ b/docs/host/devops_deployment/microk8s_linux/index.html @@ -0,0 +1,19 @@ + + + + + +Ethereal Engine on MicroK8s (Linux) | etherealengine + + + + +
+

Ethereal Engine on MicroK8s (Linux)

This guide is intended for local environment and currently tested on Ubuntu.

Install Python 3

In your WSL Ubuntu terminal, if python 3 (pip3 --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y python3-pip

You can verify pip3 by using pip3 --version command.

Install Make

In your WSL Ubuntu terminal, if make (make --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y build-essential

You can verify make by using make --version command.

Install kubectl, Helm and Docker

If kubectl, Helm and Docker aren't already installed on your machine, install them.

You may also need to install Docker Compose

Download and install MicroK8s

Instructions can be found here

sudo snap install microk8s --classic --channel=1.26/stable

Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.

While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it.

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal.

git clone https://github.com/etherealengine/etherealengine.git etherealengine

If .env.local file does not exist in the root of your repo folder then create it by duplicating .env.local.default.

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_microk8s.sh.

Enabling MicroK8s Addons

Execute following command in your terminal to enable MicroK8s addons

sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3

Add MicroK8s to Kubectl

First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run kubectl config get-contexts command in terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:

kubectl config delete-context microk8s
kubectl config delete-cluster microk8s-cluster
kubectl config delete-user microk8s-admin

Now, we will add microk8s configuration to kubectl config. We can do this by using following commands. Reference

kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt
kubectl config set-credentials microk8s-admin --token="$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')"
kubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin

Afterwards you can use this newly create context by executing kubectl config use-context microk8s

Now if you run kubectl config get-contexts command then microk8s should be current context.

(Optional) Add MicroK8s to Lens

If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool Lens. Else you can print the configuration using following command:

microk8s config

Option 1: If you have kubectl already installed, use sudo gedit ~/.kube/config as add the above output in it.
+Option 2: In Lens, goto File > Add Cluster and paste the output of above command to add cluster.

Enable MicroK8s access for local docker

For MicroK8s we will be using MicroK8s local registry

Add the following lines to /etc/docker/daemon.json. On Linux, this is done by running sudo gedit /etc/docker/daemon.json.

{ 
"insecure-registries" : ["localhost:32000"]
}

Afterwards, restart docker with: sudo systemctl restart docker

Verify and troubleshoot MicroK8s

Run sudo microk8s inspect and check if there is any warning. Its recommended to fixed the warning for MicroK8s to work properly. Following are some of the warnings and their possible fixes:

  1. WARNING: This machine's hostname contains capital letters and/or underscores. This is not a valid name for a Kubernetes node, causing node registration to fail. Please change the machine's hostname or refer to the documentation for more details.

    Possible Fix: https://askubuntu.com/a/87687/1558816

  2. WARNING: The memory cgroup is not enabled. The cluster may not be functioning properly. Please ensure cgroups are enabled

    Possible Fix: https://github.com/canonical/microk8s/issues/1691#issuecomment-1265788228

  3. WARNING: IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: sudo iptables -P FORWARD ACCEPT

    The change can be made persistent with: sudo apt-get install iptables-persistent

  4. MicroK8s is not running. Use microk8s inspect for a deeper inspection.

    Possible Fix: https://lightrun.com/answers/canonical-microk8s-microk8s-is-not-running-microk8sinspect-showing-no-error

    Here this error cloud be due to conflicting kubectl being installed. Use this command to remove kubectl sudo rm -rf /usr/local/bin/kubectl

Update system hostfile to point to MicroK8s

You'll need to edit your hostfile to point certain domains to host machine IP address. On Linux, this is done by running sudo gedit /etc/hosts.

Add/Update the following lines:

127.0.0.1 local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org

The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod.

Make sure to save this file after you've edited it. On Linux, at least, you need root permissions to edit it.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at MicroK8s by running kubectl config current-context, which should say 'microk8s'. You can also run kubectl config get-contexts to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state.

(Optional) Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana

Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update local.microk8s.template.values.yaml env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

local.microk8s.template.values.yaml can be found in ethereal-engine-ops repo.

Run build_microk8s.sh

When microk8s is running, run the following command from the root of the Ethereal Engine repo:

./scripts/build_microk8s.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached.

Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting http://localhost:32000/v2/_catalog.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Run the following command: helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine.

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/microk8s_windows/index.html b/docs/host/devops_deployment/microk8s_windows/index.html new file mode 100644 index 000000000000..5ddf81f214b1 --- /dev/null +++ b/docs/host/devops_deployment/microk8s_windows/index.html @@ -0,0 +1,18 @@ + + + + + +Ethereal Engine on MicroK8s (Windows) | etherealengine + + + + +
+

Ethereal Engine on MicroK8s (Windows)

This guide is intended for local environment and currently tested on Windows 11.

Install Windows Subsystem for Linux (WSL)

Install Ubuntu distribution of Linux from Microsoft Store by using guide here.

Alternatively, you can follow these instructions as well:

Once WSL is installed, make sure to:

Set Ubuntu as default WSL distribution

In powershell/cmd run following command to see the list of distributions:

wsl -l

In the list you should be able to see Ubuntu listed. Afterwards, run following command to set Ubuntu as default distribution:

wsl -s Ubuntu

WSL Ubuntu Default Distribution

Install Docker Desktop

Install docker desktop with WSL 2 backend. You can find the instructions here.

Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting Settings > Resources > WSL Integration. Make sure to hit 'Apply & Restart'.

Docker Desktop WSL Distro

Enable systemd in WSL

Inside your Ubuntu instance, add the following modification to /etc/wsl.conf.

[boot]
systemd=true

Then restart your instance by running wsl --shutdown in PowerShell and relaunching Ubuntu. Upon launch you should have systemd running. You can check this with the command systemctl list-unit-files --type=service which should show your services status.

You can read more about this on Ubuntu blog & Microsoft blog.

Enable localhostForwarding in WSL

Create or update .wslconfig file located at C:\Users\{USER_NAME}\.wslconfig (Or %UserProfile%\.wslconfig) with following content:

[wsl2]
localhostForwarding=true

This requires WSL shutdown and reboot. Shutting down your terminal is insufficient. Also machine boot is not required. Simply run:

wsl --shutdown (in Powershell) or 
wsl.exe --shutdown (within Ubuntu)

Reference: Custom hostname for servers running in WSL 2

Install Node

In your WSL Ubuntu terminal, if node (node --version) isn't already installed on your machine. You can do so by first installing nvm by running following commands:

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source ~/.profile

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

You can verify nvm by using nvm --version command. Afterwards, install node by using:

nvm install --lts

You can verify nvm by using node --version command.

Install Python 3

In your WSL Ubuntu terminal, if python 3 (pip3 --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y python3-pip

You can verify python3 by using python3 --version command.

Install Make

In your WSL Ubuntu terminal, if make (make --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y build-essential

You can verify make by using make --version command.

Install kubectl and Helm

In your WSL Ubuntu terminal, if kubectl & Helm aren't already installed on your machine, install them.

Docker & Docker Compose should be installed if you successfully completed "Install Docker Desktop" step. You can verify by running docker --version & docker-compose --version commands in WSL Ubuntu terminal.

Download and install MicroK8s

Make sure to install MicroK8s in your WSL Ubuntu terminal. Instructions can be found here

sudo snap install microk8s --classic --channel=1.26/stable

Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.

While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it.

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal.

git clone https://github.com/etherealengine/etherealengine.git etherealengine

If .env.local file does not exist in the root of your repo folder then create it by duplicating .env.local.default.

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_microk8s.sh.

Enabling MicroK8s Addons

Execute following command in your WSL Ubuntu terminal to enable MicroK8s addons

sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3

Add MicroK8s to Kubectl

First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run kubectl config get-contexts command in WSL Ubuntu terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:

kubectl config delete-context microk8s
kubectl config delete-cluster microk8s-cluster
kubectl config delete-user microk8s-admin

Now, we will add microk8s configuration to kubectl config. We can do this by using following commands in WSL Ubuntu terminal. Reference

kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt
kubectl config set-credentials microk8s-admin --token="$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')"
kubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin

Afterwards you can use this newly create context by executing:

kubectl config use-context microk8s

Now if you run kubectl config get-contexts command then microk8s should be current context.

(Optional) Add MicroK8s to Lens

If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool Lens. Else you can print the configuration using following command:

microk8s config

In Lens, goto File > Add Cluster and paste the output of above command to add cluster.

Enable MicroK8s access for local docker

For MicroK8s we will be using MicroK8s local registry

Option 1: In Windows, add the following lines to %userprofile%\.docker\daemon.json. Create this file if it does not already exists.

{ 
"insecure-registries" : ["http://microk8s.registry:32000", "microk8s.registry:32000"]
}

Afterwards, restart docker from Powershell: restart-service *docker*

Option 2: Edit configuration as shown in below image. Make sure to hit 'Apply & Restart' after making changes.

Docker Desktop Configuration

Reference:

Verify and troubleshoot MicroK8s

Run following command and check if there is any warning. Its recommended to fix the warnings for MicroK8s to work properly.

sudo microk8s inspect

Update system hostfile to point to MicroK8s

You'll need to edit your hostfile to point certain domains to host machine IP address. First you need to find the IP address of your WSL. Run wsl hostname -I in powershell/cmd. For example:

C:\Users\hanzl>wsl hostname -I
172.31.89.133 10.1.215.0

Note: If you face issue while running above command, make sure that 'Ubuntu' distribution is selected as default. You can do so by running wsl /l to view distributions and then run wslconfig /s Ubuntu to select distribution.

From the above output, use 172.31.89.133 as {WSL_IP}.

Note: Your ip would be different, this is just for example.

Next, edit your Windows hostfile, this is done by editing C:\Windows\System32\drivers\etc\hosts. Add/Update the following lines:

{WSL_IP} local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org

{WSL_IP} microk8s.registry

Make sure to replace {WSL_IP} with ip address from wsl hostname -I command.

The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod.

Make sure to save this file after you've edited it. Also, you will need to update hostfile with updated ip address after every Windows/WSL reboot.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at MicroK8s by running kubectl config current-context, which should say 'microk8s'. You can also run kubectl config get-contexts to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state.

(Optional) Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana

Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update local.microk8s.template.values.yaml env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

local.microk8s.template.values.yaml can be found in ethereal-engine-ops repo.

Run build_microk8s.sh

When microk8s is running, run the following command from the root of the Ethereal Engine repo in WSL Ubuntu terminal:

export REGISTRY_HOST=microk8s.registry; export MYSQL_HOST=kubernetes.docker.internal;bash ./scripts/build_microk8s.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your WSL terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached.

Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting http://microk8s.registry:32000/v2/_catalog.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Before this step, ensure that all the agones and redis pods are in "Running" state. You can check pods status using the below command.

kubectl get pods

Run the following command:

helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/minikube/index.html b/docs/host/devops_deployment/minikube/index.html new file mode 100644 index 000000000000..2315ffe5e6d0 --- /dev/null +++ b/docs/host/devops_deployment/minikube/index.html @@ -0,0 +1,59 @@ + + + + + +Ethereal Engine on Minikube | etherealengine + + + + +
+

Ethereal Engine on Minikube

Install kubectl, Helm, Docker, and VirtualBox

If kubectl, Helm, +Docker and/or VirtualBox +aren't already installed on your machine, install them.

You may also need to install Docker Compose

Download and install minikube

Instructions can be found here

While you can follow the demo instructions there about starting minikube, deploying +some demo deployments, etc. to get a feel for it, before deploying Ethereal Engine you should delete +your minikube cluster, since we have some specific starting requirements.

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local +services, you'll need to get the Ethereal Engine repo on your machine. This is most easily +done by running git clone https://github.com/etherealengine/etherealengine.git

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_minikube.sh.

Create minikube cluster

Run the following command: +minikube start --disk-size 40000m --cpus 4 --memory 10124m --addons ingress --driver virtualbox

This says to start minikube with 40GB of disk space, 4 CPUs, 10GB of memory, using VirtualBox as its +driver, and starting up an nginx ingress service.

The disk space, CPUs, and memory allocation are configurable. These are what we recommend for optimal +running (though the disk space might be a bit more than necessary). When minikube is running, +it will reserve those resources for itself regardless of whether the services in minikube are using +that much.

The 10GB of memory might be the spec with the least wiggle room. Later instructions on building +the Docker image will have it be built in the minikube context. This uses the RAM reserved for minikube, +and the client build process normally uses about 8GB of RAM at its peak. minikube may freeze if +it gets maxed out on RAM, and the Docker build process might freeze indefinitely.

Starting ingress after minikube has started

If you forget to use --addons ingress when starting minikube, you can start nginx later by +running minikube addons enable ingress

Get minikube IP address and edit system hostfile to point to

Run this command after minikube has started: minikube ip +This will get you the address that minikube is running on.

You'll need to edit your hostfile to point certain domains to minikube IP addresses. On Linux, +this is done by running sudo gedit /etc/hosts.

Add the following lines:

<Output of 'minikube ip'>  local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org
10.0.2.2 host.minikube.internal

The first line says to point several *-local.etherealengine.org domains internally to the minikube cluster, +where the nginx ingress server will redirect the traffic to the appropriate pod. +The second line is used to give minikube access to your local environment, particularly so that it +can access the MariaDB server.

Make sure to save this file after you've edited it. On Linux, at least, you need root permissions +to edit it.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at minikube by running kubectl config current-context, +which should say 'minikube'. You can also run kubectl config get-contexts to get all contexts +that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to minikube, from the top of the Ethereal Engine repo, run +helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones +and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in minikube. After a minute or so, +all of these pods should be in the Running state.

Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana

Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update local.minikube.template.values.yaml env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

local.minikube.template.values.yaml can be found in ethereal-engine-ops repo.

Run build_minikube.sh

When minikube is running, run the following command from the root of the Ethereal Engine repo:

./scripts/build_minikube.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

This points Docker in the current terminal to minikube's Docker environment. Anything that Docker builds +will be locally accessible to minikube; if the first main command in the script were not run, Docker would build to your +machine's Docker environment, and minikube would not have access to it.

The script also builds the full-repo Docker image using several build arguments. Vite, which builds +the client files, uses some information from the MariaDB database created for minikube deployments +to fill in some variables, and needs database credentials. The script will supply default values +for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, +VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your minikube deployment +accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different +domain, then you'll have to set those three environment variables to what you want them to be (and also +change the hostfile records you made pointing those subdomains to minikube's IP)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for +different services, it will only run the parts needed for that service. This may take up to 15 minutes, +though later builds should take less time as things are cached.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. Its mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Run the following command: helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine.

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api +servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers +(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run +helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. +The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/release_helm_chart/index.html b/docs/host/devops_deployment/release_helm_chart/index.html new file mode 100644 index 000000000000..69b8985af8a2 --- /dev/null +++ b/docs/host/devops_deployment/release_helm_chart/index.html @@ -0,0 +1,16 @@ + + + + + +Release Helm Chart | etherealengine + + + + +
+

Release Helm Chart

Following are the steps that needs to be taken in order to update etherealengine helm charts repo:

  • Have a checked-out copy of https://github.com/EtherealEngine/ethereal-engine-helm, set to the gh-pages branch
  • Have a checked-out copy of https://github.com/EtherealEngine/ethereal-engine-ops, set to the master branch
  • Set working directory to local ethereal-engine-ops folder
  • Increase the version number in etherealengine/Chart.yaml
  • Run helm package etherealengine
  • Run helm repo index --url https://helm.etherealengine.org .
  • Copy etherealengine-X.Y.Z.tgz that's generated to the root of the ethereal-engine-helm repo, and make sure to git add it.
  • Open index.yaml. Under entries.xrengine, there should be an entry for the new version.
  • Copy that entry to ethereal-engine-helm's index.yaml, making sure to put it under the right entries section; we've got etherealengine-builder and etherealengine in the same file, so pay attention to which one you're putting it in. Also make sure that the spacing/indentation matches the other entries.
  • Copy the generated line from index.yaml to ethereal-engine-helm/index.yaml, overwriting the generated line that's there.
  • Commit this, and push it to the gh-pages branch of ethereal-engine-helm. Within a couple of minutes, you should see the new version appear at https://helm.etherealengine.org/
+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/setup_github_oauth_for_projects/index.html b/docs/host/devops_deployment/setup_github_oauth_for_projects/index.html new file mode 100644 index 000000000000..f768d96804d7 --- /dev/null +++ b/docs/host/devops_deployment/setup_github_oauth_for_projects/index.html @@ -0,0 +1,85 @@ + + + + + +How to set up GitHub to install external projects | etherealengine + + + + +
+

How to set up GitHub to install external projects

Ethereal Engine is extensible via Projects, which can contain +new scenes, new avatars, new static resources, additional code, and more. Ethereal Engine integrates +with GitHub to push and pull projects for backup and restoration, and one can also install existing +projects from GitHub. In order to install projects from private repositories, or to push local project +changes to a GitHub repo, an OAuth app from GitHub (not a GitHub app, that is something different) needs to be +created, and the logged-in user must be connected in Ethereal Engine to GitHub (i.e. must have logged in via +GitHub at some point) and have permission to access the source and destination repositories.

Note that it is recommended that you complete most of this before the initial installation of +your deployment, so that you can log in via GitHub and be granted admin status as the first +logged-in user. If you do not, then you will either need to manually insert some of these values +into the database so that you can log yourself in; have another log method configured already +and use that logged-in admin user; or reset the database with these values configured in the +updated Helm configuration that is used for the reset.

Create a GitHub OAuth App in an organization, or your user

You can either create an OAuth App for your personal GitHub account or for an organization that +you have sufficient permissions on. Either will work for this setup.

The general instructions for doing this can be found here. +The specifics you'll need to enter are as follows:

  • Application name: Anything you want
  • Homepage URL: Whatever you want, this is just what is linked to from the OAuth authorization page
  • Authorization callback URL: enter https://api.<domain>/oauth/github/callback, e.g. https://api.example.com/oauth/github/callback. ^
  • Enable Device Flow: Leave unchecked

^If you are running this locally off of localhost, this should be https://localhost:3030/oauth/github/callback. +If you are using an explicit IP address instead of localhost, then use that IP address here, but keep the :3030, +as that is the port that the API server runs on, and GitHub needs to call back to the API server.

Create client secret, note Client ID

Once the app has been created, you will be redirected to the General settings for it. +Here, you will generate one credential for the app, so that your deployment can be authenticated.

Make note of Client ID

Near the top of this page is the Client ID for the app. This is a public ID for the app. +It will be used when configuring Ethereal Engine.

Generate client secret

Below Client ID is a section Client secrets. None are created by default, so click the +button Generate a new client secret. As the notifications that appear say, you will only see the +full secret right now, so copy it somewhere retrievable (but not anywhere publicly accessible). If +you ever lose the secret, you can always generate a new one.

Configure Ethereal Engine deployment with IDs/keys

Pre-initial installation

If you have not done the initial installation/deployment yet, then you can add most of the values +above to the Helm configuration, and they will be inserted into the database so that GitHub login +is enabled from the start, and you can then log in via GitHub and be granted admin status.

Enter the Client ID for GITHUB_CLIENT_ID, and the Client secret for +GITHUB_CLIENT SECRET in the section api.extraEnv. It is advised that you enclose all of these in +double quotes in the .yaml file, so that they are interpreted as strings even if they start with a +number, e.g. GITHUB_CLIENT_ID: "17592577832789234" If you see GITHUB_APP_ID, it is not used; +it is left over from a prior implementation of GitHub Apps, which no longer works.

Continue with the setup instructions. When you run helm install with your configuration file, the +GitHub credentials will be included.

Post-installation, if you have another authentication method configured

If you have already installed the platform but configured it with another login method, such as +email or another OAuth provider, then log in as an admin user. If you haven't logged in with anything +yet, then the first user that logs in will be made an admin.

Go to /admin/settings. Click on the Authentication selector. A page should open with a +section OAuth that takes up the bottom two-thirds. Under GitHub, enter +the Client ID under Key and the Client Secret under Secret. Click the Save button at the bottom.

Post-installation, if you do not have any authentication method configured

If you have already set up the platform but did not configure any authentication method, +then you are in a bit of a bind where you can't log in to get admin privileges, but need admin +privileges to configure an authentication method. The way around this is to reset the database +and provide the GitHub credentials as part of this process - this is similar to what would happen +on initial installation. Note that this will erase anything you've done so far, but without any +admins, the most you'd have been likely to do is change some guest users' avatars.

Open your Helm configuration. Enter the Client ID for GITHUB_CLIENT_ID and the Client secret for +GITHUB_CLIENT SECRET in the section api.extraEnv. It is advised that you enclose all of these in +double quotes in the .yaml file, so that they are interpreted as strings even if they start with a +number, e.g. GITHUB_CLIENT_ID: "17592577832789234"

Next, run helm upgrade --reuse-values -f <path/to/configuration.yaml> --set-string api.extraEnv.FORCE_DB_REFRESH=true <stage_name> etherealengine/etherealengine. +This tells Helm to restart the API servers, and for them to wipe the database and reseed it with the values +in the configuration file. It should only take a minute or two, and you should then run +helm upgrade --reuse-values --set-string api.extraEnv.FORCE_DB_REFRESH=false <stage_name> etherealengine/etherealengine to unset +the flag telling it to reset the database.

Once this is done, you should be able to log in with GitHub and be granted admin status.

Logging in with GitHub and Granting Access to Other Organizations

When you log in with GitHub, you will be asked to grant access to your user information as well as the repositories +that the OAuth app has authorized for. Ethereal Engine will have access to your personal repositories and, +if the OAuth app was created in a GitHub organization, all repositories in that organization. It will not +have inherent push access to other organizations' repositories or pull access to their private repositories.

There are two ways to grant access to other repositories. When you are first signing in via GitHub and are +presented with the screen to authorize the OAuth app's permissions, you should see a section near the bottom +that shows all of the organizations you are in. If you have admin rights to that organization, you can Grant +access. If you do not have admin rights, then you can Request access, and someone who does have admin rights +will have to approve it.

If you have already gone through the OAuth approval page, it will not be shown again - all subsequent logins +will bypass this page1. In order to grant the OAuth app access to other organizations, follow +these steps

In short form:

  1. Go to (https://github.com/settings/applications)
  2. Click on the name of the OAuth app installed in Ethereal Engine
  3. Under Organization access, click on Grant/Request for the organizations you want Ethereal Engine to +have access to

Installing Ethereal Engine projects from GitHub

See the section 'Graphical Install Flow for more information on how to install +projects from GitHub.

User Repo Access to GitHub (with optional webhooks)

Users can push projects to GitHub if they have write/maintain/admin access to the associated GitHub repository. +Since fetching this access from the GitHub API every time a user fetches their projects can take a noticeable +amount of time, Ethereal Engine stores users' GitHub repo access in its database. This is much faster to access.

There are multiple actions that will make the engine re-fetch and update users' repo access:

  • When a user logs in via GitHub
  • When a user clicks on the button "Refresh GitHub Repo Access" on /admin/projects or /studio (must be logged +in as a user that is associated with a GitHub account)
  • Via a GitHub webhook - must manually configure this

Setting up GitHub webhook

Ethereal Engine currently only supports webhook notifications for Collaborators being added/edited/removed. +Changes in Teams are not handled by Ethereal Engine due to the opacity of team members. (Team change webhooks do not +include team members, and the engine does not track who is in a team)

An admin needs to go to /admin/settings, click on 'Server', then enter a secret key in the field +"GitHub Webhook Secret", then click the Save button. The secret can be any string you make up. +Randomly generated strings are encouraged.

Next, go to GitGub. In the Repository or Organization that you want to send updates for, go to +Settings -> Code(, planning,) and automation -> Webhooks, then click "Add webhook".

For Payload URL, enter <your_api_subdomain>/github-repo-access-webhook, e.g. https://api.example.com/github-repo-access-webhook +Set Content Type to application/json. For Secret, enter the secret from the earlier step. For +"Which events would you like to trigger this webhook?", select "Let me select individual events." +In the list of events that appears, uncheck "Pushes", anf check "Collaborator add, remove, or changed". +At the very bottom of the page, click the green button "Add webhook".

After the webhook is created, the webhook will send a ping request to the API endpoint you provided. If the URL +was entered correctly, and the secret was entered correctly in both ends, the ping should get a 200 response. +You can check the status under the "Recent Deliveries" tab of that webhook on GitHub.

When this is working, whenever a user is added, removed, or has their access modified, the engine +will re-fetch the user's full set of GitHub repo accesses and update the database's records.

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started/index.html b/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started/index.html new file mode 100644 index 000000000000..ab23f8d2d8ea --- /dev/null +++ b/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started/index.html @@ -0,0 +1,17 @@ + + + + + +Getting Started | etherealengine + + + + +
+

Getting Started

The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster.

We know it's been complicated to build with Ethereal Engine and we've made this tool to give the community easy access to the engine. We would love to see your creations and invite you all to come build with us.

App Overview

The Ethereal Engine Control Center app provides access to various functionalities which includes:

  • Configure your Ethereal Engine in a cluster in just a few clicks.
  • View status of Ethereal Engine dependencies on your local system.
  • Manage an Ethereal Engine deployment through admin panel.
  • Manage kubernetes cluster through its dashboard.
  • Manage IPFS node running in the cluster.
  • Execute commands against rippled server.
  • See realtime logs of different actions being performed.

1. Downloading Control Center App

In order to download Ethereal Engine Control Center App, navigate to releases page and download the latest version of the App. On Windows (and for WSL), you will need to download .exe while for linux download AppImage.

On Windows, you will need to allow permission for executing ps1 scripts. You can do so by running following command in Powershell with admin privileges (reference).

Set-ExecutionPolicy -ExecutionPolicy Unrestricted

On Linux, once downloaded, right click and go to Properties of AppImage. In Permissions tab check 'Allow executing file as program'. Afterwards, double click on AppImage to launch the app.

On Ubuntu 22.04 or later, if you are unable to launch AppImage then you might have to install Fuse using following command in terminal (reference).

sudo apt-get install fuse libfuse2

2. Launch & Create Cluster

When you launch the app for the first time, you will see below screen:

Home Screen

Here you need to create a cluster. You can do so by clicking on Create button in the center or anytime using round plus button on left bottom corner (in hotbar) of the screen. Following are the different sections of create cluster dialog:

2.1. Cluster Information

Create Cluster - Cluster Information

In this step, you will need to provide following information:

  • Cluster Name: This can be any name you want to give your cluster. i.e. Local, my-metaverse, etc.

  • Cluster Type: This will be the kubernetes distribution you want to use. Currently there are 2 local distributions, MicroK8s(recommended) & Minikube. There is also a Custom type which allows you to connect to an existing Ethereal Engine cluster.

    Currently, MicroK8s is supported on Windows & Linux while Minikube is supported on Linux only.

  • Prerequisites: These are the set of items that should be manually configured by the user. If an item is correctly setup then its status will be green tick, else it will have a red cross with details and link to docs for the corrective measures.

    Currently, there are prerequisites for MicroK8s in Windows only.

2.2. Cluster Type: MicroK8s or Minikube

If you selected cluster type as MicroK8s or Minikube, then you will see below options.

2.2.1. Authentication

Create Cluster - Authentication

In this step, you need to provide sudo password for linux terminal. This is because Control Center App will perform various actions on your system with admin privileges.

On Windows, this is the password of your WSL Ubuntu distribution's sudo user.

2.2.2. Configurations

Create Cluster - Configurations

In this step, you will need to provide following information:

  • Engine Path: This is the location of ethereal engine source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Ops Path: This is the location of ethereal engine ops source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Enable Ripple Stack: By default you should keep this option as off unless you want to have IPFS & rippled server running in your local K8s deployment.

  • Force DB Refresh: This will truncate database tables & repopulate them with seed data.

    If the database is empty, then Control Center App will itself force populate it.

2.2.3. Variables

Create Cluster - Variables

In this step for most of the users, go with the default variable values and leave the text fields as it is.

For advanced setup, if you want to configure oAuth, S3 file storage, email, SMS support then you can provide variable values.

2.2.4. Summary

Create Cluster - Summary

This step will show a summary of all the previous steps. User can review them before proceeding ahead.

Please make sure to read Note on this screen.

Afterwards, there are following option(s):

  • Create: By default you should go with this option as it will create the cluster entry and show the cluster screen of this cluster.

  • Create & Configure: This will create the cluster entry and show the current status of things. And afterwards it will automatically start the configuration script to ensure things are setup.

If you use 'Create' option, then you can still run the Configure script as discussed later in this guide.

2.3. Cluster Type: Custom

If you selected Custom cluster type, then you will see below options. Custom cluster allows to connect to an existing kubernetes cluster.

2.3.1. Kubeconfig

Create Cluster - Kubeconfig

In this step, you will need to provide following information regarding desired cluster's kubeconfig:

  • Config Type - Default: This will load the default kubeconfig file of your system.

  • Config Type - File: This will allow to load kubeconfig from a file of your system.

  • Config Type - Text: This will allow to load kubeconfig from a text.

  • Context: This is the selected kube context of cluster in which your ethereal engine deployment exists. The dropdown will show all contexts that exist in selected config type.

2.3.2. Deployment

Create Cluster - Deployment

In this step, you will need to provide following deployment information:

  • Release Name: This is the name of your release in selected kubernetes deployment. It can be 'dev', 'prod', 'local', etc.

    Release name is used to prefix the workloads in your cluster like: +{RELEASE_NAME}-etherealengine-client. i.e. prod-etherealengine-client

2.3.3. Summary

Create Cluster - Summary

This step will show a summary of all the previous steps. User can review them before proceeding ahead.

Please make sure to read Note on this screen.

Afterwards, there are following option(s):

  • Create: This option will create the cluster entry and show the workloads screen of this cluster.

3. Cluster Screen

Cluster Screen

Once you have created a cluster you will be navigated to its screen also know as config page. Lets explain various sections of this screen:

3.1. Hotbar

Hotbar

It will show you a list of all clusters you have created. You can click on each of them to view the cluster screen of them.

Add Cluster Icon The plus icon at the bottom of this bar is used to create a new cluster.

3.2. Navbar

Navbar

This section allows navigation and various utility options. Following are the various options in it:

  • App Icon: App Icon Logo of this application.

  • Home Icon: Home Icon Navigate to home.

  • Config: Navigates to cluster screen of selected cluster.

  • Workloads: Navigates to workloads screen of selected cluster.

  • Admin: Navigates to ethereal engine admin panel of selected cluster.

  • K8 Dashboard: Navigates to kubernetes web dashboard of selected kubernetes distribution.

  • IPFS: Navigates to IPFS web UI of selected cluster. This option is visible only if ripple stack is enabled.

  • Rippled CLI: Navigates to rippled server cli of selected cluster. This option is visible only if ripple stack is enabled.

  • Change Theme Icon: Change Theme Icon Allows to toggle between vaporware, light & dark themes. The color scheme of these themes are similar to ethereal engine.

  • Support Icon: Support Icon Opens a dropdown menu to allow reaching out to support via Discord or Github.

  • User Icon: User Icon The functionality for this button is coming soon.

3.3. Options Panel

Options Panel

This section shows various actions against currently selected cluster. Following are the options in it:

  • Cluster Icon: Cluster Icon Logo of the selected cluster type. It can be MicroK8s or Minikube logo.

  • Cluster Name: This is the cluster name that you entered in create cluster dialog. i.e. Local.

  • Engine Git Status: Cluster Icon This is used to view current status of local ethereal engine github repo. You can view & change current branch, view & pull incoming changes, view & push outgoing changes.

  • Ops Git Status: Cluster Icon This is used to view current status of local ethereal engine ops github repo. You can perform all actions as explained for engine git status.

  • Refresh Icon: Refresh Icon This will recheck the status of prerequisites, system, apps & engine. It also, recheck the status of engine and ops git repos. If a refresh is already in process then it will be disabled until its finished.

  • Delete Icon: Delete Icon This will delete a clusters. It would not make any changes in associated local kubernetes, app, etc.

  • Settings Icon: Settings Icon This will open settings dialog. It contains some selected cluster specific settings in addition to general app settings.

  • Configure Button: Configure Button This will open the configure dialog which is discussed later. If a configuration is already running then this button will be disabled and have a spinner in it.

  • Launch Button: Launch Button This button will open Ethereal Engine's default location in your browser as discussed later.

3.4. System Status

System Status

This section will show the current status of whether the system requirements are meet or not. On Windows, it will also show the status of prerequisites.

The status against each item will be displayed. You can find more details by hovering over Info Icon info icon. This info icon is useful when some item is not configured correctly.

Additionally, for some items you will see Fix Icon auto fix icon. Clicking this button will try to auto fix the problem. Though if it fails, you can try using configure dialog which is discussed later.

Usually, auto fix button should only be used if previously you were able to run the cluster successfully. Otherwise, use configure dialog.

3.5. Apps Status

Apps Status

This section will show the current status of all the apps required to run ethereal engine deployment.

3.6. Engine Status

Engine Status

This section will show the current status of various components of ethereal engine deployment in your local kubernetes distribution.

3.7. Logs

Logs

This section will show all the logs of current session. The logs are of the different actions being performed by control center and their output.

  • Download Button: Download Button This will download all displayed logs.

  • Clear Button: Clear Button This will clear all displayed logs.

4. Configure Cluster

On (cluster screen), if any of the status is not green tick then it means you need to run the configure script to fix them automatically. To do so use the Configure (Configure Button) button in the options panel. Following are the different sections of configure cluster dialog:

Its always recommended to clear your logs before running configure script in order to trace outputs easily.

4.1. Authentication

Configure Cluster - Authentication

In this step, you need to provide sudo password for linux terminal. This is because Control Center App will perform various actions on your system with admin privileges.

On Windows, this is the password of your WSL Ubuntu distribution's sudo user.

4.2. Configurations

Configure Cluster - Configurations

In this step, you will need to provide following information:

  • Engine Path: This is the location of ethereal engine source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Ops Path: This is the location of ethereal engine ops source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Enable Ripple Stack: By default you should keep this option as off unless you want to have IPFS & rippled server running in your local K8s deployment.

  • Force DB Refresh: This will truncate database tables & repopulate them with seed data.

    If the database is empty, then Control Center App will itself force populate it.

4.3. Variables

Configure Cluster - Variables

In this step for most of the users, go with the default variable values and leave the text fields as it is.

For advanced setup, if you want to configure oAuth, S3 file storage, email, SMS support then you can provide variable values.

4.4. Summary

Configure Cluster - Summary

This step will show a summary of all the previous steps. User can review them before proceeding ahead.

Please make sure to read Note on this screen.

Afterwards, there are following option(s):

  • Configure: This will start the configuration script which will ensure things are setup. You can track output of various things in logs. Depending on your system and status of apps, it can take a while to setup things. As the configure script is executing, the Configure (Configure Button) button will be disabled and have a spinner in it.

    Once the script finished its execution, the cluster status will be automatically refreshed.

    If the configure script failed, pay close attention to last few lines of logs section. As it will contain the reason why script failed.

5. Launch Ethereal Engine

Launch Ethereal Engine

Once, everything is configured correctly and all ticks are green on config page (Cluster Screen) then you can click on Launch button in options panel. This button will open Ethereal Engine's default location in your browser.

Make sure to allow certificates as explained here.

6. Workloads

Workloads

This page will show current state of workloads for selected cluster. The workloads are mainly the k8s pods of various components of ethereal engine. In addition to options panel, following the sections of this screen:

6.1. Workload Tabs

Workload Tabs

This section allows to filter based on various workload types. Default tab will be All, which displays all workloads. The number below each tab's label will display the currently ready count followed by slash and then total count.

6.2. Workloads Table

Workloads Table

This section will display data based on selected workload tab. For each workload, it will contain pod name and other details. Hovering over a container's circle will display further details. Moreover, there is a Logs button to view kubernetes container logs as discussed in next section. Delete button will allow to remove the pod from current kubernetes distribution.

Additionally, there is refresh icon button on right top of this table. This will refresh/reload data being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval.

6.3. Workload Logs

Workload Logs

This section will by default display cluster logs. Though if user clicked Logs button as discussed in previous section, then the logs of that workload will be displayed. The cluster logs will then be displayed under Config log tab. User can toggle between these log tabs, while workload logs can be closed as well.

The download and clear icon button will perform actions based on selected log's tab. Additionally for workload logs, there is refresh icon button on right top of this section. This will refresh/reload logs being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval.

Beside these icons there is also a container drop down through which user can select the workload's pod container for which logs are displayed.

7. Admin Dashboard

Admin Dashboard

Once, everything is configured correctly and all ticks are green on config page (Cluster Screen) then you can click on Admin button in navbar. This will show the admin dashboard of ethereal engine deployed in your local k8s cluster.

You can perform various actions from admin dashboard including installing projects, managing users, groups, locations, instances, resources, etc.

8. K8 Dashboard

K8 Dashboard

Once, your selected local k8s distribution (Microk8s or Minikube) has a green tick on config page (Cluster Screen) then you can click on K8 Dashboard button in navbar. This will show the k8s dashboard.

For MicroK8s, when you launch it for the first time then you will be asked regarding token configurations. You can use Skip button to pass through it.

K8 Dashboard Token

You can perform various actions from k8s dashboard including managing pods, jobs, deployments, services, etc.

9. IPFS

IPFS Web UI

If ripple stack is enabled and once, IPFS has a green tick on config page (Cluster Screen) then you can click on IPFS button in navbar. This will show the IPFS web UI.

You can view and manage various aspects of the IPFS running in your local cluster using this dashboard. IPFS is not required by default for engine, though for custom use cases it can be used.

10. Rippled CLI

Rippled CLI

If ripple stack is enabled and once, Rippled has a green tick on config page (Cluster Screen) then you can click on Rippled CLI button in navbar. This will show the Rippled CLI page.

You can run various commands against rippled server and view their outputs. Rippled is not required by default for engine, though for custom use cases it can be used.

11. Updating the App

Every time you launch control center app it will check for the latest version of the app. If there is an update, then it will prompt to update. Its always recommend to use the latest version of the app.

+ + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/tutorials/ethereal_control_center/index.html b/docs/host/devops_deployment/tutorials/ethereal_control_center/index.html new file mode 100644 index 000000000000..9ab355737cfe --- /dev/null +++ b/docs/host/devops_deployment/tutorials/ethereal_control_center/index.html @@ -0,0 +1,16 @@ + + + + + +Control Center App | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/tutorials/index.html b/docs/host/devops_deployment/tutorials/index.html new file mode 100644 index 000000000000..0804347bd0a6 --- /dev/null +++ b/docs/host/devops_deployment/tutorials/index.html @@ -0,0 +1,16 @@ + + + + + +Tutorials | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/host/devops_deployment/upgrade_helm_deployment/index.html b/docs/host/devops_deployment/upgrade_helm_deployment/index.html new file mode 100644 index 000000000000..b440c189baa0 --- /dev/null +++ b/docs/host/devops_deployment/upgrade_helm_deployment/index.html @@ -0,0 +1,16 @@ + + + + + +Upgrading Helm Release | etherealengine + + + + +
+

Upgrading Helm Release

This guide will cover various sections regarding upgrading an existing helm deployment.

Getting Updated values.yaml File

Usually a helm release upgrade is required when changes are made in configuration of helm charts. To do so first thing required is value.yaml file of current configuration. If you already have an updated copy of this file then you can update the desired values and push the changes to helm deployment.

But for scenarios where multiple people are working same deployment, it becomes difficult to maintain updated values.yaml file. At anytime you can get the current version/snapshot of values.yaml file by running get values command:

helm get values [DEPLOYMENT_NAME]

i.e.

helm get values dev

You can save the output in a values.yaml file and update the required values.

Evaluating Difference in value.yaml & Deployed Charts

It become very handy if you can evaluate the differences between your local values.yaml file and current deployment. This way you can beforehand visualize the changes a helm upgrade is going to make. To do so first make sure you have helm diff plugin installed. You can install it by running:

helm plugin install https://github.com/databus23/helm-diff

Once helm diff plugin is installed then you can run following command:

helm diff upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --values [PATH_TO_VALUES_YAML]

i.e.

helm diff upgrade dev etherealengine/etherealengine --values ~/etherealengine-ops/values/dev.ethereal.values.yaml

This will print the output of differences between deployed helm release and changes in specified values.yaml file. Incase the output is empty, it means there is no difference/changes.

Upgrading Helm Deployment

Once the local values.yaml file is updated, it can be reflect to deployment using following commands:

helm upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --reuse-values -f [PATH_TO_VALUES_YAML]

i.e.

helm upgrade dev etherealengine/etherealengine --reuse-values -f ~/etherealengine-ops/values/dev.ethereal.values.yaml
+ + + + \ No newline at end of file diff --git a/docs/host/index.html b/docs/host/index.html new file mode 100644 index 000000000000..b1540f51e45d --- /dev/null +++ b/docs/host/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal for Hosts | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/docs/host/installation/advanced_setup/index.html b/docs/host/installation/advanced_setup/index.html new file mode 100644 index 000000000000..ee8ca3e2aa0b --- /dev/null +++ b/docs/host/installation/advanced_setup/index.html @@ -0,0 +1,46 @@ + + + + + +Advanced Setup | etherealengine + + + + +
+

Advanced Setup

If you want to setup Ethereal Engine docker instances, client, server, and/or +instance-server manually, follow these directions. The advanced setup is recommended +for all users, in order to understand more about everything that's going on.

1. Install your dependencies

cd path/to/etherealengine
npm install
npm run dev-docker
npm run dev-reinit

You should not need to use sudo in any case.

Error with mediasoup? https://mediasoup.org/documentation/v3/mediasoup/installation/

  • Check your version of python is up to date
  • Ensure your install path has no whitespaces

2. Make sure you have a mysql database installed and running -- our recommendation is Mariadb.

We've provided a docker container for easy setup:

cd scripts && sudo bash start-db.sh

This creates a Docker container of mariadb named etherealengine_db. You must have +docker installed on your machine for this script to work. +If you do not have Docker installed and do not wish to install it, you will have +to manually create a MariaDB server.

The default username is 'server', the default password is 'password', the +default database name is 'etherealengine', the default hostname is '127.0.0.1', and +the default port is 3306.

Seeing errors connecting to the local DB? Try shutting off your local firewall.

3. Open a new tab and start the Agones sidecar in local mode

cd scripts
sudo bash start-agones.sh

You can also go to vendor/agones/ and run

./sdk-server.linux.amd64 --local

If you are using a Windows machine, run

sdk-server.windows.amd64.exe --local

and for mac, run

./sdk-server.darwin.amd64 --local

4. Start the server in database seed mode

Several tables in the database need to be seeded with default values. +Run npm run dev-reinit or if on windows npm run dev-reinit-windows +After several seconds, there should be no more logging. +Some of the final lines should read like this:

Server Ready
Executing (default): SET FOREIGN_KEY_CHECKS = 1
Server EXIT

At this point, the database has been seeded.

5. Local file server configuration (Optional)

If the .env.local file you have has the line +STORAGE_PROVIDER=local +then the scene editor will save components, models, scenes, etc. locally +(as opposed to storing them on S3). You will need to start a local server +to serve these files, and make sure that .env.local has the line +LOCAL_STORAGE_PROVIDER="localhost:8642". +In a new tab, go to packages/server and run npm run serve-local-files. +This will start up http-server to serve files from packages/server/upload +on localhost:8642. +You may have to accept the invalid self-signed certificate for it in the browser; +see 'Allow local file http-server connection with invalid certificate' below.

6. Open two/three separate tabs and start the API server, instanceserver and client

In /packages/server, run npm run dev which will launch the api server, world server, media server and file server. +If you are not using instanceservers, you can instead run npm run dev-api-server in the api server. +In the final tab, go to /packages/client and run npm run dev. +If you are on windows you need to use npm run dev-windows instead of npm run dev.

7. In a browser, navigate to https://127.0.0.1:3000/location/default

The database seeding process creates a default empty location called 'default'. +It can be navigated to by going to 'https://127.0.0.1:3000/location/default'. +As of this writing, the cert provided in the ethereal engine package for local use is +not adequately signed. You can create signed certificates and replace the +default ones, but most developers just ignore the warnings. Browsers will throw +up warnings about going to insecure pages. You should be able to tell the browser +to ignore it, usually by clicking on some sort of 'advanced options' button or +link and then something along the lines of 'go there anyway'.

+ + + + \ No newline at end of file diff --git a/docs/host/installation/basic_setup/index.html b/docs/host/installation/basic_setup/index.html new file mode 100644 index 000000000000..b98935f88dee --- /dev/null +++ b/docs/host/installation/basic_setup/index.html @@ -0,0 +1,34 @@ + + + + + +Basic Setup | etherealengine + + + + +
+

Basic Setup

Installation

Getting up and running requires just a few steps, but this can be tricky, +depending on your platform and current environment. Please follow the directions +for your environment.

Pre-Install Checklist

  • Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less
  • Clone the repository
  • Install Node.js 16 or 18 (earlier versions not guaranteed to work)
  • Install Python >=3.6 + PIP, C++, and +other build tools. See the Mediasoup install instructions +for full details.
  • Install Docker
    • (Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's .env.local accordingly.

You should now be ready to follow the Quick Start instructions.

Clone the repository

A lot has changed during development, and our monorepo has gotten quite large. +To avoid cloning the entire thing, use this command:

git clone https://github.com/etherealengine/etherealengine --depth 1

Ensure you are running Node 16 or 18

The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions +are not guaranteed to work properly.

A version manager can be helpful for this:

Before running the engine, please check node --version +If you are using a node version below 16, please update or nothing will work. +You will know you are having issues if you try to install at root and are +getting dependency errors.

Docker is your friend

You don't need to use Docker, but it will make +your life much easier. +If you don't wish to use Docker, you will need to setup mariadb and redis on +your machine. You can find credentials in /scripts/docker-compose.yml

Quick Start

If you are lucky, this will just work. However, you may encounter some +issues. Make sure you are running Node 16, and check your dependencies.

cd path/to/etherealengine
cp .env.local.default .env.local
npm install
npm run dev-docker
npm run dev-reinit
npm run dev

Now run Ethereal Engine in browser by navigating to this link.

Accept Certificates

You'll have to tell your browser to ignore the insecure connections when you try to load the website.

  1. If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates.
  2. Open Developer tools in your browser by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I) and then go to the 'Console' tab.
  3. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab.
  4. You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.

Admin System and User Setup

You can administrate many features from the admin panel at https://localhost:3000/admin

To make a user an admin, open a page and open the profile menu. There is a button labelled Show User ID +which opens a text field with your userId. Paste it in and run the following command in +your terminal:

npm run make-user-admin -- --id={COPIED_USER_ID}

Example: +npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac

image

Alternate Method:

Look up in User table and change userRole to 'admin' +(It helps to use a graphical database explorer, we recommend beekeeperstudio.io)

Test user Admin privileges by going to /admin

Advanced Installation and Troubleshooting

If you run into any trouble with the Quick Start instructions:

+ + + + \ No newline at end of file diff --git a/docs/host/installation/docker/index.html b/docs/host/installation/docker/index.html new file mode 100644 index 000000000000..b654598e20f2 --- /dev/null +++ b/docs/host/installation/docker/index.html @@ -0,0 +1,20 @@ + + + + + +Old Docker Instructions | etherealengine + + + + +
+

Old Docker Instructions

You can quickstart locally using docker, if you don't have node installed or +just want to test the latest.

Get local IP address

Use a tool like ifconfig to get your local IP address.

Start local databases

cd scripts
docker-compose up

When the logging stops, that indicates that the databases have been created and +are running.

Ctrl+c out of that, then from scripts run ./start-all-docker.sh +(This must be run every time you start your machine anew)

Build the image

Create an empty folder at the root called project-package-jsons and then run +the following command to build:

DOCKER_BUILDKIT=1 docker build -t etherealengine --build-arg MYSQL_USER=server \
--build-arg MYSQL_PASSWORD=password --build-arg MYSQL_HOST=127.0.0.1 \
--build-arg MYSQL_DATABASE=etherealengine --build-arg MYSQL_PORT=3304 \
--build-arg VITE_SERVER_HOST=localhost --build-arg VITE_SERVER_PORT=3030 \
--build-arg VITE_INSTANCESERVER_HOST=localhost --build-arg VITE_INSTANCESERVER_PORT=3031 \
--build-arg VITE_LOCAL_BUILD=true --build-arg CACHE_DATE="$(date)" --network="host" .

Run the server to seed the database, wait a couple minutes, then delete it

docker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "FORCE_DB_REFRESH=true" --network host etherealengine
docker logs server -f
-Wait for the line "Server Ready", then Ctrl+c out of the logs-
docker container stop server
docker container rm server

Run the images

docker run -d --name serve-local --env-file .env.local.default -e "SERVER_MODE=serve-local" --network host etherealengine
docker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine
docker run -d --name client --env-file .env.local.default -e "SERVER_MODE=client" --network host etherealengine
docker run -d --name world --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine
docker run -d --name channel --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" -e "INSTANCESERVER_PORT=3032" --network host etherealengine

Delete containers, if you want to run a new build, or just get rid of them

docker container stop serve-local
docker container rm serve-local
docker container stop server
docker container rm server
docker container stop client
docker container rm client
docker container stop world
docker container rm world
docker container stop channel
docker container rm channel
+ + + + \ No newline at end of file diff --git a/docs/host/installation/index.html b/docs/host/installation/index.html new file mode 100644 index 000000000000..060fcedc54b0 --- /dev/null +++ b/docs/host/installation/index.html @@ -0,0 +1,34 @@ + + + + + +Installation | etherealengine + + + + +
+

Installation

Getting up and running requires just a few steps, but this can be tricky, +depending on your platform and current environment. Please follow the directions +for your environment.

Pre-Install Checklist

  • Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less
  • Clone the repository
  • Install Node.js 16 or 18 (earlier versions not guaranteed to work)
  • Install Python >=3.6 + PIP, C++, and +other build tools. See the Mediasoup install instructions +for full details.
  • Install Docker
    • (Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's .env.local accordingly.

You should now be ready to follow the Quick Start instructions.

Clone the repository

A lot has changed during development, and our monorepo has gotten quite large. +To avoid cloning the entire thing, use this command:

git clone https://github.com/etherealengine/etherealengine --depth 1

Ensure you are running Node 16 or 18

The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions +are not guaranteed to work properly.

A version manager can be helpful for this:

Before running the engine, please check node --version +If you are using a node version below 16, please update or nothing will work. +You will know you are having issues if you try to install at root and are +getting dependency errors.

Docker is your friend

You don't need to use Docker, but it will make +your life much easier. +If you don't wish to use Docker, you will need to setup mariadb and redis on +your machine. You can find credentials in /scripts/docker-compose.yml

Quick Start

If you are lucky, this will just work. However, you may encounter some +issues. Make sure you are running Node 16, and check your dependencies.

cd path/to/etherealengine
cp .env.local.default .env.local
npm install
npm run dev-docker
npm run dev-reinit
npm run dev

Now run Ethereal Engine in browser by navigating to this link.

Accept Certificates

You'll have to tell your browser to ignore the insecure connections when you try to load the website.

  1. If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates.
  2. Open Developer tools in your browser by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I) and then go to the 'Console' tab.
  3. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab.
  4. You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.

Admin System and User Setup

You can administrate many features from the admin panel at https://localhost:3000/admin

To make a user an admin, open a page and open the profile menu. There is a button labelled Show User ID +which opens a text field with your userId. Paste it in and run the following command in +your terminal:

npm run make-user-admin -- --id={COPIED_USER_ID}

Example: +npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac

image

Alternate Method:

Look up in User table and change userRole to 'admin' +(It helps to use a graphical database explorer, we recommend beekeeperstudio.io)

Test user Admin privileges by going to /admin

Advanced Installation and Troubleshooting

If you run into any trouble with the Quick Start instructions:

+ + + + \ No newline at end of file diff --git a/docs/host/installation/install_troubleshooting/index.html b/docs/host/installation/install_troubleshooting/index.html new file mode 100644 index 000000000000..5530951245cb --- /dev/null +++ b/docs/host/installation/install_troubleshooting/index.html @@ -0,0 +1,36 @@ + + + + + +Troubleshooting | etherealengine + + + + +
+

Troubleshooting

Browser Debug

p key debug colliders view

Invalid Certificate errors in local environment

As of this writing, the cert provided in the ethereal engine package for local use +is not adequately signed. Browsers will throw up warnings about going to insecure pages. +You should be able to tell the browser to ignore it, usually by clicking on some sort +of 'advanced options' button or link and then something along the lines of 'go there anyway'.

Chrome sometimes does not show a clickable option on the warning. If so, just +type badidea or thisisunsafe when on that page. You don't enter that into the +address bar or into a text box, Chrome is just passively listening for those commands.

Allow instanceserver address connection via installing local Certificate Authority

For more detailed instructions check: https://github.com/FiloSottile/mkcert

Short version (common for development process on Ubuntu):

  1. Execute sudo apt install libnss3-tools
  2. Execute brew install mkcert (if you don't have brew, check it's page: https://brew.sh/)
  3. Execute mkcert --install
  4. Navigate to ./certs folder
  5. Execute mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1

Allow local file http-server connection with invalid certificate

Open the developer tools in your browser by pressing Ctrl+Shift+i at the +same time. Go to the 'Console' tab and look at the message history. If there are +red errors that say something like +GET https://127.0.0.1:3030/socket.io/?EIO=3&transport=polling&t=NXlZLTa net::ERR_CERT_AUTHORITY_INVALID, +then right-click that URL, then select 'Open in new tab', and accept the invalid certificate.

Allow instanceserver address connection with invalid certificate

The instanceserver functionality is hosted on an address other than 127.0.0.1 in the local +environment. Accepting an invalid certificate for 127.0.0.1 will not apply to this address. +Open the dev console for Chrome/Firefox by pressing Ctrl+Shift+i simultaneously, and +go to the Console or Network tabs.

If you see errors about not being able to connect to +something like https://192.168.0.81:3031/socket.io/?location=<foobar>, right click on +that URL and open it in a new tab. You should again get a warning page about an invalid +certificate, and you again need to allow it.

AccessDenied connecting to mariadb

Make sure you don't have another instance of mariadb running on port 3306

lsof -i :3306

On Linux, you can also check if any processes are running on port 3306 with +sudo netstat -utlp | grep 3306 +The last column should look like <ID>/<something +You can kill any running process with sudo kill <ID>

Error: listen EADDRINUSE :::3030

Check which process is using port 3030 and kill

killall -9 node 

Or

lsof -i :3030
kill -3 <proccessIDfromPreviousCommand>

'CORS error' in terminal

Try accessing the page using https://localhost:3000 +instead of https://127.0.0.1:3000

Default blank screen

Try typing “thisisunsafe” or "iknowwhatiamdoing" then reload page

Instanceserver or resource loading error?

Open dev console, click on the GET link in new tab and accept certificate by +typing thisisunsafe” or "iknowwhatiamdoing" then reload original page

To install a new package for editor react components in monorepo

Type in terminal

     npm i <packagename> -w @etherealengine/editor

Using Local Storage instead of MinIO

Currently MinIO is used as default storage for local development. If you want to use local storage then do following steps:

  • set VITE_FILE_SERVER to the commented values under # Use following value for local file server and comment out the values above it.
  • set STORAGE_PROVIDER to local

Accessing MinIO S3 storage provider running in local docker

Using MinIO Console:

  • When MinIO contain is running in your docker, navigate to https://localhost:9001/ in your browser.

    Make sure to accept invalid certificate warning.

  • Login using username as server and password as password.

    You can find these credentials in scripts/docker-compose.yml as MINIO_ROOT_USER & MINIO_ROOT_PASSWORD

Using S3 Browser (Windows Only):

  • Download & install S3 Browser from https://s3browser.com/download.aspx.
  • Launch and connect using following details:
    • Account Type: S3 Compatible Storage
    • REST Endpoint: 127.0.0.1:9000
    • Access Key ID: server
    • Secret Access Key: password
    • Use secure transfer (SSL/TLS): Check / On / True

Clear all data from MinIO S3 storage provider running in local docker

Run following commands in your terminal:

  docker container stop etherealengine_minio_s3
docker container rm etherealengine_minio_s3
docker container prune --force
docker volume prune --force
npm run dev-docker
npm run dev-reinit

DB not seeding routes (E.g. Error: No project installed- please contact site admin)

Try

  npm run dev-reinit 

or

  docker container stop etherealengine_db
docker container rm etherealengine_db
docker container prune --force
npm run dev-docker
npm run dev-reinit

Weird issues with your database?

Try

npm run dev-reinit

Or if on windows

npm run dev-reinit-windows
+ + + + \ No newline at end of file diff --git a/docs/host/installation/mac_os_x/index.html b/docs/host/installation/mac_os_x/index.html new file mode 100644 index 000000000000..1acfa9766ef2 --- /dev/null +++ b/docs/host/installation/mac_os_x/index.html @@ -0,0 +1,23 @@ + + + + + +Installing on Mac OS X | etherealengine + + + + +
+

Installing on Mac OS X

  1. Go to the root and run
npm install
npm run dev-docker
npm run dev-reinit

Or if you are on a M1 based Mac

(Recommended) +1) Duplicate the Terminal app, and configure it to run in Rosetta +2) Run the above in Rosetta Terminal

(Not recommended)

yarn install

This is because on Apple chips the node-darwin sometimes doesn't get installed +properly and by using yarn it fixes the issue.

  1. Have docker started in the background and then in the terminal type
npm run dev

This will open the mariaDB and SQL scripts on the docker and will start the servers

  1. To make sure your environment is set and running properly just go to +https://localhost:3000/location/default and you should be able to walk around an empty 3D scene
Note : Make sure you are on Node >= 16 and have docker running. 

Troubleshooting Mac

  • If you find issues on your terminal that says that access-denied for user +server@localhost then you can use this command
brew services stop mysql
  • If you find issue on your terminal that says +An unexpected error occurred: "expected workspace package +while using yarn then you can use this command in your terminal
yarn policies set-version 1.18.0

As yarn > 1.18 sometimes doesn't work properly with lerna.

+ + + + \ No newline at end of file diff --git a/docs/host/installation/opensearch/index.html b/docs/host/installation/opensearch/index.html new file mode 100644 index 000000000000..5f1dd45885b1 --- /dev/null +++ b/docs/host/installation/opensearch/index.html @@ -0,0 +1,16 @@ + + + + + +Logging with Opensearch on Docker | etherealengine + + + + +
+

Logging with Opensearch on Docker

If you want to quickstart with detailed logging using opensearch, Please follow this guide.

Setup Opensearch on Docker locally

Pull OpenSearch Images

OpenSearch

docker pull opensearchproject/opensearch:latest

OpenSearch Dashboard

docker pull opensearchproject/opensearch-dashboards:latest

Start Opensearch Containers

OpenSearch

docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" -e "plugins.security.disabled=true" opensearchproject/opensearch:latest 

OpenSearch Dashboard

docker run -it -d --network="host" -e "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true" opensearchproject/opensearch-dashboards:latest

Verify if the containers are up & running

  • Send a request to port 9200
    curl http://127.0.0.1:9200
  • List Indices through curl
    curl -X GET "http://127.0.0.1:9200/_cat/indices?v"
  • Create Indices through Curl
    curl -X PUT "http://127.0.0.1:9200/your_index_name"
  • Delete Index
    curl --location --request DELETE 'http://127.0.0.1:9200/index_name'
  • Fetch logs for an index_name
    curl --location --request GET 'http://127.0.0.1:9200/ethereal/_search' \
--header 'Content-Type: application/json' \
--data '{
"query": {
"match_all": {}
},
"size": 10000
}'

Enable Client Logging

Set VITE_FORCE_CLIENT_LOG_AGGREGATE to true to enable client log aggregation

VITE_FORCE_CLIENT_LOG_AGGREGATE=true

Enable Server Logging

Set DISABLE_SERVER_LOG=false to false to enable server log aggregation

DISABLE_SERVER_LOG=false

Note: These changes in the .env.local file will ensure proper communication with OpenSearch and enable client and server log aggregation

+ + + + \ No newline at end of file diff --git a/docs/host/installation/running_on_static_IP/index.html b/docs/host/installation/running_on_static_IP/index.html new file mode 100644 index 000000000000..c7208316fedc --- /dev/null +++ b/docs/host/installation/running_on_static_IP/index.html @@ -0,0 +1,26 @@ + + + + + +Running on Static IP under WSL2 | etherealengine + + + + +
+

Running on Static IP under WSL2

Follow these steps to run the engine on a static IP instead of localhost. In +most cases you should be able to simply access the engine using the public IP +assigned to your device, but if you run into any issues or if you are running +the stack on WSL2 then you can refer to the following directions.

  1. Replace all localhost values with the static IP you want to run the stack on +in your .env.local file.
  2. Open a PowerShell terminal as admin. And run the wsl2-port-forwarding.ps1 +script present under /scripts directory. +Note: Make sure all of the required ports are present in ports array of the +wsl2-port-forwarding.ps1 script.
  3. And now just run the engine as you normally would and everything should be +accessible over the static IP.
  4. If you get any errors related to localhost:8642, then make sure that none of +the assets in your scene have been saved localhost path. If there are then +replace localhost with the static IP in the respective asset's path too.
+ + + + \ No newline at end of file diff --git a/docs/host/installation/windows/index.html b/docs/host/installation/windows/index.html new file mode 100644 index 000000000000..a208af49d9e7 --- /dev/null +++ b/docs/host/installation/windows/index.html @@ -0,0 +1,17 @@ + + + + + +Installing on Windows 10+ | etherealengine + + + + +
+

Installing on Windows 10+

  1. Install python 3 and add python installation directory path to 'PATH' env variable.
  2. Install node js
  3. Install Visual studio community edition with build tools.

    Note: If mediasoup is not installed properly then modify Visual studio setup to add c++ and Node.js support.

  4. Add path of MSbuild.exe (which is present in visual studio folder) into 'path' env variable (for example: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin)
  5. Make sure to install all windows prerequisites for mediasoup as mentioned on: https://mediasoup.org/documentation/v3/mediasoup/installation/#windows
  6. Install all dependencies using npm i.
  7. If error persists then check for typos in environment variables.
  8. If you are on Windows, you can use docker-compose to start the scripts/docker-compose.yml file, or install mariadb and copy credentials (database name, username, password) from docker-compose or .env.local -- you will need to create an empty database with the matching name.

./start-db.sh only needs to be run once. If the docker image has stopped, start it again with:

docker container start etherealengine_db
  1. Check your WSL config for any incorrect networking settings. +https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network
+ + + + \ No newline at end of file diff --git a/docs/host/installation/windows_wsl/index.html b/docs/host/installation/windows_wsl/index.html new file mode 100644 index 000000000000..87d107601337 --- /dev/null +++ b/docs/host/installation/windows_wsl/index.html @@ -0,0 +1,20 @@ + + + + + +Installing on Windows with WSL2 | etherealengine + + + + +
+

Installing on Windows with WSL2

This guide is currently tested on Windows 10 (22H2) and Windows 11.

Install Windows Subsystem for Linux (WSL).

Remember to run Powershell in Administrator mode either by right clicking and selecting 'Run as administrator' or by typing PowerShell in 'Run' dialog box of Windows and pressing Ctrl+Shift+Enter key combination.

Install Ubuntu distribution of Linux by executing the command: +wsl --install --distribution Ubuntu +or +Install Ubuntu distribution of Linux from Microsoft Store by using guide here.

Alternatively, you can follow these instructions as well:

Once WSL is installed, make sure to:

Install Docker Desktop

Install docker desktop with WSL 2 backend. You can find the instructions here.

Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting Settings > Resources > WSL Integration. Enable integration with Ubuntu. Make sure to hit 'Apply & Restart'.

Docker Desktop WSL Distro

Install Node.

Run Powershell in Administrator mode. Run Ubuntu using command : wsl. After logging on run the following command: cd ~/ to ensure that the installation of Node and other packages mentioned below is done in Ubuntu.

In your WSL Ubuntu terminal, if node (node --version) isn't already installed on your machine. You can do so by first installing nvm by running following commands:

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source ~/.profile

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

You can verify nvm by using nvm --version command. Afterwards, install Node (version between 16.0 and 18.0 both inclusive) by using:

nvm install --lts

You can verify node version by using node --version command.

Install Python 3

In your WSL Ubuntu terminal, if python 3 (pip3 --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y python3-pip

You can verify python3 by using python3 --version command.

Install Make

In your WSL Ubuntu terminal, if make (make --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y build-essential

You can verify make by using make --version command.

Clone Ethereal Engine repo to your local machine

Clone Ethereal Engine repo on your machine by running following command in WSL Ubuntu terminal. You can check the directory in which you are sitting by the command: pwd

git clone https://github.com/etherealengine/etherealengine --depth 1

Change directory to the location where etherealengine repo is cloned cd etherealengine +If .env.local file does not exist in the root of your repo folder then create it by duplicating .env.local.default. Command: cp .env.local.default .env.local

Afterwards, install npm packages using:

npm install

Note: If you face issue related to mediasoup while doing npm install. Then remove the mediasoup package from packages/instanceserver/package.json file of Ethereal Engine source code. And run npm install again. Afterwards, run:

npm install mediasoup@3 -w @etherealengine/instanceserver

Initialize MariaDB server

If you are running the engine for the first time then you will need to initialize the database with tables and data. You can do so by running:

npm run dev-reinit

Start Engine Stack

You can run Ethereal Engine stack by running:

npm run dev

Now run Ethereal Engine in browser by navigating to this link.

Accept Certificates

You'll have to tell your browser to ignore the insecure connections when you try to load the website.

  1. If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates.
  2. Open Developer tools in your browser by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I) and then go to the 'Console' tab.
  3. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab.
  4. You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.
+ + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000000..7e2e89b722b9 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,22 @@ + + + + + +Overview | etherealengine + + + + +
+

Ethereal Engine

Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for +any reason - to host events, make games, showcase art, or just to provide a space for your community. There are plenty of platforms on which you can spend a bit to have a world, but you can't be in complete control of the experience or customise it from the ground up.

When the Ethereal Engine stack is deployed, that stack is sovereign, open and cross +platform by default. Users can create any kind of game or experience with no limits. +With the tech that's being built now, users will be able to seamlessly travel +through portals from any worlds to any other world, on different servers, and have all +their data and identity travel with them.

This technology is for everyone, but especially people who want to build or +belong to a community.

WebXR Engine

The core engine is the heart of Ethereal Engine. Based around the WebXR spec, brought to life with libraries such as threejs, bitecs, rapier.js, Mediasoup WebRTC, reactjs & hookstatejs. With the latest understanding of Data-Oriented Design, ECS and Event-Sourcing paradigms, we have put together a robust MMO XR framework that rivals AAA capabilities, quality and speed.

On The Web

Built for the web, Ethereal Engine providers a fully customisable and clean UI that works in both immersive and non-immersive contexts, as well as an administration panel for full control of deployment, locations, projects, avatars, custom routes & more.

Deployment Stack

Running on the backend is a state of the art fullstack framework, template & deployment pipeline using kubernetes, docker, agones, openmatch & feathersjs. The result is a fully customisable and scalable web app.

Ethereal Studio

The Studio sits on top of the engine, as a heavily modified version of Mozilla Hubs' Spoke editor. It has been transformed with the engine and the web app to provide a fast and comprehensive Content Management System, file browser, cloud edge caching, content pipeline tools and other creator tools.

Project API

The Project API is the core of what makes Ethereal Engine shine - the ability to load your own scenes, assets & code with a click of a button. Using github, we allow users to have fully version controlled access to extend the base functionality. You can see examples of the Project API in action here and here

Stack Overview

+ + + + \ No newline at end of file diff --git a/es/.nojekyll b/es/.nojekyll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/es/404.html b/es/404.html new file mode 100644 index 000000000000..2d59c6ee7b1e --- /dev/null +++ b/es/404.html @@ -0,0 +1,16 @@ + + + + + +Página No Encontrada | etherealengine + + + + +
+

Página No Encontrada

No pudimos encontrar lo que buscaba.

Comuníquese con el dueño del sitio que lo vinculó a la URL original y hágale saber que su vínculo está roto.

+ + + + \ No newline at end of file diff --git a/es/assets/css/styles.6c1ddb1d.css b/es/assets/css/styles.6c1ddb1d.css new file mode 100644 index 000000000000..8a2a4840cd7f --- /dev/null +++ b/es/assets/css/styles.6c1ddb1d.css @@ -0,0 +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)}[data-theme=dark] .DocSearch,[data-theme=light] .DocSearch{--docsearch-muted-color:var(--ifm-color-secondary-darkest);--docsearch-hit-color:var(--ifm-font-color-base);--docsearch-hit-active-color:var(--ifm-color-white)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}*,.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}: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:#01022e;--ifm-color-primary-dark:#29784c;--ifm-color-primary-darker:#277148;--ifm-color-primary-darkest:#205d3b;--ifm-color-primary-light:#33925d;--ifm-color-primary-lighter:#359962;--ifm-color-primary-lightest:#3cad6e;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base)}.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}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)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{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{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}.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;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;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)}.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);color:var(--ifm-font-color-base);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.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)}.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base);color:#fff!important}: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,.markdown a: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;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);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,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;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{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);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-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-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{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;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#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:#01022e;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--docusaurus-highlighted-code-line-bg:#0000004d}.docusaurus-highlight-code-line{background-color:#484d5b;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.markdown a{font-weight:500;text-decoration:underline}[data-theme=light] .DocSearch{--docsearch-container-background:#5e6470b3;--docsearch-modal-background:var(--ifm-color-secondary-lighter);--docsearch-searchbox-background:var(--ifm-color-secondary);--docsearch-searchbox-focus-background:var(--ifm-color-white);--docsearch-hit-background:var(--ifm-color-white);--docsearch-footer-background:var(--ifm-color-white)}[data-theme=dark] .DocSearch{--docsearch-text-color:var(--ifm-font-color-base);--docsearch-container-background:#2f3745b3;--docsearch-modal-background:var(--ifm-background-color);--docsearch-searchbox-background:var(--ifm-background-color);--docsearch-searchbox-focus-background:var(--ifm-color-black);--docsearch-hit-background:var(--ifm-color-emphasis-100);--docsearch-footer-background:var(--ifm-background-surface-color);--docsearch-key-gradient:linear-gradient(-26.5deg,var(--ifm-color-emphasis-200) 0%,var(--ifm-color-emphasis-100) 100%)}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.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}.DocSearch-Container a,.tag_zVej:hover{text-decoration:none}.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}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[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)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.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{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.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}.searchQueryInput_u2C7,.searchVersionInput_m0Ui{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_u2C7:focus,.searchVersionInput_m0Ui:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_u2C7::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_JPFH{font-size:.9rem;font-weight:700}.algoliaLogo_rT1R{max-width:150px}.algoliaLogoPathFill_WdUC{fill:var(--ifm-font-color-base)}.searchResultItem_Tv2o{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_KbCB{font-weight:400;margin-bottom:0}.searchResultItemPath_lhe1{--ifm-breadcrumb-separator-size-multiplier:1;color:var(--ifm-color-content-secondary);font-size:.8rem}.searchResultItemSummary_AEaO{font-style:italic;margin:.5rem 0 0}.loadingSpinner_XVxU{animation:1s linear infinite a;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes a{to{transform:rotate(1turn)}}.loader_vvXV{margin-top:2rem}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.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)}.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}.collapseSidebarButton_PEFL{display:none;margin:0}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}.heroBanner_qdFl{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_AeoN,.mdxPageWrapper_j9I6{justify-content:center}.DocSearch-Button,.DocSearch-Button-Container,.buttons_AeoN,.features_cAfv{align-items:center;display:flex}.features_cAfv{padding:2rem 0;text-align:center;width:100%}.featureImage_wMIZ{height:200px;width:200px}.hero--primary_JQ01{background-color:#01022e!important}.button_JGCe{color:#fff}.DocSearch-Button{background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Input,.DocSearch-Link{-webkit-appearance:none;font:inherit}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Hit-action-button,.DocSearch-Reset{-webkit-appearance:none;border:0;cursor:pointer}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards b;appearance:none;background:none;border-radius:50%;color:var(--docsearch-icon-color);padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border-radius:50%;color:inherit;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands li,.DocSearch-Commands-Key{align-items:center;display:flex}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}@keyframes b{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container{z-index:calc(var(--ifm-z-index-fixed) + 1)}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;list-style:none;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:"#"}.containsTaskList_mC6p{list-style:none}.img_ev3q{height:auto}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.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}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}: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)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_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%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_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)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.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}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.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 only screen and (max-width:996px){.searchQueryColumn_RTkw,.searchResultsColumn_JPFH{max-width:60%!important}.searchLogoColumn_rJIA,.searchVersionColumn_ypXd{max-width:40%!important}.searchLogoColumn_rJIA{padding-left:0!important}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{-webkit-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media screen and (max-width:576px){.searchQueryColumn_RTkw{max-width:100%!important}.searchVersionColumn_ypXd{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@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 (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width);animation:none;-webkit-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/es/assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png b/es/assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png new file mode 100644 index 000000000000..e9a8ce173f2a Binary files /dev/null and b/es/assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png differ diff --git a/es/assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg b/es/assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg new file mode 100644 index 000000000000..812105e5bb2c Binary files /dev/null and b/es/assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg differ diff --git a/es/assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg b/es/assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg new file mode 100644 index 000000000000..2618f7eda64b Binary files /dev/null and b/es/assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg differ diff --git a/es/assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg b/es/assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg new file mode 100644 index 000000000000..f9fa57b8e795 Binary files /dev/null and b/es/assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg differ diff --git a/es/assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png b/es/assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png new file mode 100644 index 000000000000..3ebf610be08a Binary files /dev/null and b/es/assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png differ diff --git a/es/assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg b/es/assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg new file mode 100644 index 000000000000..283f50fb48e0 Binary files /dev/null and b/es/assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg differ diff --git a/es/assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg b/es/assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg new file mode 100644 index 000000000000..23c95a8735f2 Binary files /dev/null and b/es/assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg differ diff --git a/es/assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg b/es/assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg new file mode 100644 index 000000000000..84b578fb6eae Binary files /dev/null and b/es/assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg differ diff --git a/es/assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg b/es/assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg new file mode 100644 index 000000000000..f0195240d0a6 Binary files /dev/null and b/es/assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg differ diff --git a/es/assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg b/es/assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg new file mode 100644 index 000000000000..6618a75cc4b5 Binary files /dev/null and b/es/assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg differ diff --git a/es/assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg b/es/assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg new file mode 100644 index 000000000000..4bb069363c0c Binary files /dev/null and b/es/assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg differ diff --git a/es/assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg b/es/assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg new file mode 100644 index 000000000000..150330b21071 Binary files /dev/null and b/es/assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg differ diff --git a/es/assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg b/es/assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg new file mode 100644 index 000000000000..c4bd453225f8 Binary files /dev/null and b/es/assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg differ diff --git a/es/assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg b/es/assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg new file mode 100644 index 000000000000..fcee7c6bfa1a Binary files /dev/null and b/es/assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg differ diff --git a/es/assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg b/es/assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg new file mode 100644 index 000000000000..8f3980b70718 Binary files /dev/null and b/es/assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg differ diff --git a/es/assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg b/es/assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg new file mode 100644 index 000000000000..8ea7e8b4209c Binary files /dev/null and b/es/assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg differ diff --git a/es/assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg b/es/assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg new file mode 100644 index 000000000000..50862947d2e6 Binary files /dev/null and b/es/assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg differ diff --git a/es/assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg b/es/assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg new file mode 100644 index 000000000000..e653c196effb Binary files /dev/null and b/es/assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg differ diff --git a/es/assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png b/es/assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png new file mode 100644 index 000000000000..180c9eb66301 Binary files /dev/null and b/es/assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png differ diff --git a/es/assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png b/es/assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png new file mode 100644 index 000000000000..3150502b3c24 Binary files /dev/null and b/es/assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png differ diff --git a/es/assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png b/es/assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png new file mode 100644 index 000000000000..424a297f5067 Binary files /dev/null and b/es/assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png differ diff --git a/es/assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png b/es/assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png new file mode 100644 index 000000000000..c944d7ca3ec2 Binary files /dev/null and b/es/assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png differ diff --git a/es/assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png b/es/assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png new file mode 100644 index 000000000000..be9ec3c46285 Binary files /dev/null and b/es/assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png differ diff --git a/es/assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg b/es/assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg new file mode 100644 index 000000000000..f5731e866180 Binary files /dev/null and b/es/assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg differ diff --git a/es/assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg b/es/assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg new file mode 100644 index 000000000000..a51a914ca883 Binary files /dev/null and b/es/assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg differ diff --git a/es/assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg b/es/assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg new file mode 100644 index 000000000000..5bc868a9784c Binary files /dev/null and b/es/assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg differ diff --git a/es/assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg b/es/assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg new file mode 100644 index 000000000000..d5424a72e659 Binary files /dev/null and b/es/assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg differ diff --git a/es/assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg b/es/assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg new file mode 100644 index 000000000000..873f3202fe41 Binary files /dev/null and b/es/assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg differ diff --git a/es/assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg b/es/assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg new file mode 100644 index 000000000000..563b6364421a Binary files /dev/null and b/es/assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg differ diff --git a/es/assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg b/es/assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg new file mode 100644 index 000000000000..40bb9d674a15 Binary files /dev/null and b/es/assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg differ diff --git a/es/assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg b/es/assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg new file mode 100644 index 000000000000..2025da78c27f Binary files /dev/null and b/es/assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg differ diff --git a/es/assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg b/es/assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg new file mode 100644 index 000000000000..7b22c8ba97db Binary files /dev/null and b/es/assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg differ diff --git a/es/assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg b/es/assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg new file mode 100644 index 000000000000..9608ee30d7f1 Binary files /dev/null and b/es/assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg differ diff --git a/es/assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png b/es/assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png new file mode 100644 index 000000000000..cb2ba7a3ff77 Binary files /dev/null and b/es/assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png differ diff --git a/es/assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg b/es/assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg new file mode 100644 index 000000000000..72dd3c02db13 Binary files /dev/null and b/es/assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg differ diff --git a/es/assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg b/es/assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg new file mode 100644 index 000000000000..9334ccb8d3f1 Binary files /dev/null and b/es/assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg differ diff --git a/es/assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png b/es/assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png new file mode 100644 index 000000000000..4937f74d8562 Binary files /dev/null and b/es/assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png differ diff --git a/es/assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png b/es/assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png new file mode 100644 index 000000000000..3a33108a003e Binary files /dev/null and b/es/assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png differ diff --git a/es/assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png b/es/assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png new file mode 100644 index 000000000000..4dd09d97df27 Binary files /dev/null and b/es/assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png differ diff --git a/es/assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png b/es/assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png new file mode 100644 index 000000000000..b6e348900a5b Binary files /dev/null and b/es/assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png differ diff --git a/es/assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png b/es/assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png new file mode 100644 index 000000000000..b078df2480f0 Binary files /dev/null and b/es/assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png differ diff --git a/es/assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png b/es/assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png new file mode 100644 index 000000000000..f541b315f370 Binary files /dev/null and b/es/assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png differ diff --git a/es/assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png b/es/assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png new file mode 100644 index 000000000000..aca69f881efd Binary files /dev/null and b/es/assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png differ diff --git a/es/assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png b/es/assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png new file mode 100644 index 000000000000..7990acea71e5 Binary files /dev/null and b/es/assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png differ diff --git a/es/assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png b/es/assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png new file mode 100644 index 000000000000..961dbdce5aba Binary files /dev/null and b/es/assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png differ diff --git a/es/assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png b/es/assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png new file mode 100644 index 000000000000..30ba4ae3abab Binary files /dev/null and b/es/assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png differ diff --git a/es/assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png b/es/assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png new file mode 100644 index 000000000000..94d2e8260be9 Binary files /dev/null and b/es/assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png differ diff --git a/es/assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png b/es/assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png new file mode 100644 index 000000000000..a4aa61a36b4b Binary files /dev/null and b/es/assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png differ diff --git a/es/assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg b/es/assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg new file mode 100644 index 000000000000..010e45e55d67 Binary files /dev/null and b/es/assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg differ diff --git a/es/assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg b/es/assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg new file mode 100644 index 000000000000..e5fdfe4520c0 Binary files /dev/null and b/es/assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg differ diff --git a/es/assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png b/es/assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png new file mode 100644 index 000000000000..fd2d4224717d Binary files /dev/null and b/es/assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png differ diff --git a/es/assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg b/es/assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg new file mode 100644 index 000000000000..9a0339768cd7 Binary files /dev/null and b/es/assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg differ diff --git a/es/assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg b/es/assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg new file mode 100644 index 000000000000..41a80a0be699 Binary files /dev/null and b/es/assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg differ diff --git a/es/assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg b/es/assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg new file mode 100644 index 000000000000..a4cad46dd275 Binary files /dev/null and b/es/assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg differ diff --git a/es/assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg b/es/assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg new file mode 100644 index 000000000000..694bacff58f9 Binary files /dev/null and b/es/assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg differ diff --git a/es/assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png b/es/assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png new file mode 100644 index 000000000000..6d6e2a88a29f Binary files /dev/null and b/es/assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png differ diff --git a/es/assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg b/es/assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg new file mode 100644 index 000000000000..501d355ec101 Binary files /dev/null and b/es/assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg differ diff --git a/es/assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg b/es/assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg new file mode 100644 index 000000000000..db7ad2405cd9 Binary files /dev/null and b/es/assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg differ diff --git a/es/assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg b/es/assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg new file mode 100644 index 000000000000..370754935bbd Binary files /dev/null and b/es/assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg differ diff --git a/es/assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg b/es/assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg new file mode 100644 index 000000000000..fdbb001613e6 Binary files /dev/null and b/es/assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg differ diff --git a/es/assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg b/es/assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg new file mode 100644 index 000000000000..69927f6428d7 Binary files /dev/null and b/es/assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg differ diff --git a/es/assets/js/0304d7f4.280ccf8d.js b/es/assets/js/0304d7f4.280ccf8d.js new file mode 100644 index 000000000000..e2dc47938b46 --- /dev/null +++ b/es/assets/js/0304d7f4.280ccf8d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8953],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>y});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),m=o,y=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(y,i(i({ref:t},p),{},{components:r})):n.createElement(y,i({ref:t},p))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={},i="Networking",s={unversionedId:"creator/development/networking",id:"creator/development/networking",title:"Networking",description:"Networks",source:"@site/docs/2_creator/4_development/3_networking.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/networking",permalink:"/etherealengine-docs/es/docs/creator/development/networking",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/3_networking.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Entities, Components and Systems",permalink:"/etherealengine-docs/es/docs/creator/development/ecs"},next:{title:"Event Sourcing",permalink:"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing"}},c={},l=[{value:"Networks",id:"networks",level:2},{value:"Users & Peers",id:"users--peers",level:2},{value:"Ownership and Authority",id:"ownership-and-authority",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"networking"},"Networking"),(0,o.kt)("h2",{id:"networks"},"Networks"),(0,o.kt)("p",null,"Networks are a way of sharing topic specific data between certain peers. There are two types of networks, ",(0,o.kt)("strong",{parentName:"p"},"world")," and ",(0,o.kt)("strong",{parentName:"p"},"media")," networks, and are tied to location instances and media instances respectively."),(0,o.kt)("h2",{id:"users--peers"},"Users & Peers"),(0,o.kt)("p",null,"Users are unique accounts created in a particular Ethereal Engine deployment. Users can connect to multiple instances, and have multiple peers connected to each instance."),(0,o.kt)("h2",{id:"ownership-and-authority"},"Ownership and Authority"),(0,o.kt)("p",null,"Ownership specifies that a networked entity belongs to a particular user. Ownership cannot be transferred for an entity, the entity must be destroyed and recreated by a new user. "),(0,o.kt)("p",null,"Authority specifies that a networked entity can be controlled by a particular peer. Authority can be transferred between peers, and is done so by sending an authority request action to the owner peer, upon which the owner peer will send an authority transfer action to the requesting peer."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/0346e14a.62b5698b.js b/es/assets/js/0346e14a.62b5698b.js new file mode 100644 index 000000000000..33dde5623d5f --- /dev/null +++ b/es/assets/js/0346e14a.62b5698b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[720],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=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 o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),u=i,m=p["".concat(s,".").concat(u)]||p[u]||h[u]||a;return n?o.createElement(m,r(r({ref:t},d),{},{components:n})):o.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,r=new Array(a);r[0]=u;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,r[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var o=n(7462),i=(n(7294),n(3905));const a={},r="Installing Projects",l={unversionedId:"host/devops_deployment/installing_projects",id:"host/devops_deployment/installing_projects",title:"Installing Projects",description:"Local Install Flow",source:"@site/docs/1_host/2_devops_deployment/2_installing_projects.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/installing_projects",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/2_installing_projects.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on AWS",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup"},next:{title:"Database Migrations",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations"}},s={},c=[{value:"Local Install Flow",id:"local-install-flow",level:2},{value:"Graphical Install Flow",id:"graphical-install-flow",level:2},{value:"Updating the Engine Version and Rebuilding Projects",id:"updating-the-engine-version-and-rebuilding-projects",level:3}],d={toc:c},p="wrapper";function h(e){let{components:t,...a}=e;return(0,i.kt)(p,(0,o.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"installing-projects"},"Installing Projects"),(0,i.kt)("h2",{id:"local-install-flow"},"Local Install Flow"),(0,i.kt)("p",null,"To install a project locally, clone the repository you wish to install to the\n",(0,i.kt)("inlineCode",{parentName:"p"},"/packages/projects/projects/")," folder. You can do this with the follow commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd packages/projects/projects/\ngit clone https://github.com/myorg/myrepo\ncd myrepo \ncode .\n")),(0,i.kt)("p",null,"This will create a folder name ",(0,i.kt)("inlineCode",{parentName:"p"},"myrepo")," which must contain an ",(0,i.kt)("inlineCode",{parentName:"p"},"xrengine.config.ts"),"\nfile, and open the project in a new vscode window (such that git commands can be\nhandled by the new window). All you need to do now to run this project is re-run\nthe stack (with ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev"),")."),(0,i.kt)("h2",{id:"graphical-install-flow"},"Graphical Install Flow"),(0,i.kt)("p",null,"Projects can also be installed and managed from the /admin/projects route. You must be\nan admin and must have a linked GitHub account, which can be attained by having your\nGitHub account linked to your Ethereal Engine account by signing in via GitHub.\n(You do not need to have most recently signed in via GitHub, you just have to have\nlinked your GH account at some point)"),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects"},"the section 'How to set up GitHub to install external projects'"),"\nfor instructions on creating an OAuth app from GitHub, installing it into an Ethereal Engine deployment,\nand authorizing it to have access to your GitHub organizations."),(0,i.kt)("p",null,"Click the 'Add Project' button:"),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(389).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"You will see text fields for entering the source and destination repositories.\nWhen you click away from the text fields, the URL will be checked both for the\nrepository existing, and for whether you have sufficient permission to access\nthat repository - read permission for the source repo (public repositories are\nalways available), and write or admin permission for the destination repo. If\nyou have never logged into GitHub with your current account, you will not be\nallowed to add or update projects."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(5752).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"For the source repository, after entering the URL, you will also need to select\na branch to pull from. Your options are either the main branch for that repository,\nor a branch that matches the ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," of the deployment, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"dev-deployment")," for\na deployment with the environment variable ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME=dev"),". If ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," is not defined, then\n",(0,i.kt)("inlineCode",{parentName:"p"},"local")," is used; this could lead to multiple local installations of the platform conflicting,\nbut one can set ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," locally to something else in your .env.local file."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(3571).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"After the branch is selected, you also need to select a tagged commit from that branch,\nor the most recent commit. As of this writing, you must manually tag project commits yourself,\nthough tags are copied over from the source repository when installing or updating a project."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(3792).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"The backend checks that the source and destination repos have the same project.\nThe project name is the ",(0,i.kt)("inlineCode",{parentName:"p"},"name")," field in the project's package.json file.\nIf the destination repo's ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment")," branch is empty or nonexistent, then\nany project can be uploaded to it. If the destination deployment branch is not empty,\nthen it can only be updated with different versions of that project. For example,\nif the destination branch has project ",(0,i.kt)("inlineCode",{parentName:"p"},"example1")," in it, you will not be allowed to\noverwrite it with a project ",(0,i.kt)("inlineCode",{parentName:"p"},"test3"),", only other projects named ",(0,i.kt)("inlineCode",{parentName:"p"},"example1"),"."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(8618).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"You can only install a project with a given name once, and names are ",(0,i.kt)("strong",{parentName:"p"},"case-insensitive"),";\n",(0,i.kt)("inlineCode",{parentName:"p"},"example1")," is seen as the same name as ",(0,i.kt)("inlineCode",{parentName:"p"},"ExamplE1"),". You would need to remove an existing project\nin order to install a different project that has the same name, or rename one of the projects."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(463).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"When everything is valid, you will be able to click the Submit button, which will install\nthe project."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(4548).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"Adding a project through this interface runs ",(0,i.kt)("inlineCode",{parentName:"p"},"git clone")," in the background, same as above,\nbut will then upload all of the repository's files to the storage provider. These files will then be\ndownloaded and installed to the deployment's file system each time the docker builder\npod runs. This allows full version controlled access for local development flow\nand version locking for production deployment. The source project code will then be force-pushed\nto the branch ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment"),", so make sure that there is no work in that branch\nthat might get overwritten, and make a backup in another branch you do want to save it."),(0,i.kt)("p",null,"The Push to GitHub button will push the current code for that project to the ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment"),"\nbranch if possible; it will ",(0,i.kt)("em",{parentName:"p"},"never")," push to the main branch. If there are merge conflicts, it will instead\nmake a Pull Request on that branch with the changes; it will NOT force-push anything to this branch,\nunlike adding or updating a project."),(0,i.kt)("p",null,"The Update button opens the same drawer as adding a new project, just with the destination repository locked in.\nAssuming everything matches, it will also force-push to the ",(0,i.kt)("inlineCode",{parentName:"p"},"-deployment")," branch in the destination\nrepository."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(8119).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"The GitHub Repo Link button also opens this drawer, but you can only select the destination repository, not\nthe source repository, and no code is pushed anywhere. "),(0,i.kt)("p",null,"The remove button will remove the folder containing that project. This will not delete the deployment\nbranch. WARNING: Any uncommitted & unpushed files will be lost."),(0,i.kt)("h3",{id:"updating-the-engine-version-and-rebuilding-projects"},"Updating the Engine Version and Rebuilding Projects"),(0,i.kt)("p",null,"Making changes to a project is not always reflected immediately in the running code. As of this writing,\nproject code is built into the client-side and backend files, and changes to project code require that\nthe codebase be updated. Locally, this just requires you to stop and restart the ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev")," command.\nIn a production environment, this requires that the builder process be restarted, so that it can\nrebuild the client and backend code with the new project code."),(0,i.kt)("p",null,"Changes to scenes in projects do not require a rebuild - since they are stored external to the codebase\nin the storage provider, and are downloaded anew by a client each time the scene is loaded, changes to\nscenes will always be immediately available. The act of saving a project will clear any cached version\nof the scene's static files, so the client will get the new version."),(0,i.kt)("p",null,"Additionally, if you want to update the core Ethereal Engine code, you will also need to re-run the builder\nprocess with the new version of the code."),(0,i.kt)("p",null,"In a production environment, click on the button ",(0,i.kt)("inlineCode",{parentName:"p"},"Update Engine/Rebuild"),". A drawer will open with\na selector for the engine version you want to update with. This will be an image in the builder's\nlinked image repository."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(800).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"After selecting an engine version, if you click Submit now, you will just rebuild with the\nnewly-selected version of the main codebase, plus whatever versions of your projects are currently\nin your linked repositories."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(372).Z,width:"1920",height:"960"})),(0,i.kt)("p",null,"If you click on ",(0,i.kt)("inlineCode",{parentName:"p"},"Update projects"),",\nyou can select the source commits for any installed projects that have a destination repo, same as with\nthe Add/Update project drawer. The projects will be updated before the builder is restarted."),(0,i.kt)("p",null,(0,i.kt)("img",{src:n(4273).Z,width:"1920",height:"960"})))}h.isMDXComponent=!0},800:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-engine-update-select-tag-19010a5035d32028b1fe2bc108317453.png"},372:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-engine-update-solo-36db6fe4b0b041ddf53b78f68aef64ac.png"},4273:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-engine-update-with-projects-6c4881c693916e38c4aef2ed30aa7c7b.png"},5752:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-invalid-source-fda5b3cd62b53ce1974074ea9fea62cf.png"},8618:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-mismatched-projects-03be680f5576945e9e9b47e2d637cf16.png"},389:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-new-d3d0e63451648ab1fb868b3b25b55300.png"},463:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-project-exists-0afc37d54dcb96767edf6642e2dfd0cf.png"},3571:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-select-branch-74a06d0c9d8e4df49233974684896be1.png"},3792:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-select-tag-baa75d38d370f32587676c576de5baca.png"},4548:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-install-valid-submit-72370ea40fc0268f8e54e9f9f2685750.png"},8119:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/projects-admin-update-valid-submit-933ca18cc568f3829d32edecfb2dc9ff.png"}}]); \ No newline at end of file diff --git a/es/assets/js/06bf4b13.b597313d.js b/es/assets/js/06bf4b13.b597313d.js new file mode 100644 index 000000000000..f5d4b990bddb --- /dev/null +++ b/es/assets/js/06bf4b13.b597313d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5572],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>g});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 l(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 l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var i=r.createContext({}),c=function(e){var n=r.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=c(e.components);return r.createElement(i.Provider,{value:n},e.children)},u="mdxType",h={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,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(t),d=a,g=u["".concat(i,".").concat(d)]||u[d]||h[d]||l;return t?r.createElement(g,o(o({ref:n},p),{},{components:t})):r.createElement(g,o({ref:n},p))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,o=new Array(l);o[0]=d;var s={};for(var i in n)hasOwnProperty.call(n,i)&&(s[i]=n[i]);s.originalType=e,s[u]="string"==typeof e?e:a,o[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>o,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var r=t(7462),a=(t(7294),t(3905));const l={},o="Logging with Opensearch on Docker",s={unversionedId:"host/installation/opensearch",id:"host/installation/opensearch",title:"Logging with Opensearch on Docker",description:"If you want to quickstart with detailed logging using opensearch, Please follow this guide.",source:"@site/docs/1_host/1_installation/8_opensearch.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/opensearch",permalink:"/etherealengine-docs/es/docs/host/installation/opensearch",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/8_opensearch.md",tags:[],version:"current",sidebarPosition:8,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Old Docker Instructions",permalink:"/etherealengine-docs/es/docs/host/installation/docker"},next:{title:"Deployment",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/"}},i={},c=[{value:"Setup Opensearch on Docker locally",id:"setup-opensearch-on-docker-locally",level:2},{value:"Pull OpenSearch Images",id:"pull-opensearch-images",level:3},{value:"OpenSearch",id:"opensearch",level:4},{value:"OpenSearch Dashboard",id:"opensearch-dashboard",level:4},{value:"Start Opensearch Containers",id:"start-opensearch-containers",level:3},{value:"OpenSearch",id:"opensearch-1",level:4},{value:"OpenSearch Dashboard",id:"opensearch-dashboard-1",level:4},{value:"Verify if the containers are up & running",id:"verify-if-the-containers-are-up--running",level:3},{value:"Enable Client Logging",id:"enable-client-logging",level:3},{value:"Enable Server Logging",id:"enable-server-logging",level:3}],p={toc:c},u="wrapper";function h(e){let{components:n,...t}=e;return(0,a.kt)(u,(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"logging-with-opensearch-on-docker"},"Logging with Opensearch on Docker"),(0,a.kt)("p",null,"If you want to quickstart with detailed logging using opensearch, Please follow this guide. "),(0,a.kt)("h2",{id:"setup-opensearch-on-docker-locally"},"Setup Opensearch on Docker locally"),(0,a.kt)("h3",{id:"pull-opensearch-images"},"Pull OpenSearch Images"),(0,a.kt)("h4",{id:"opensearch"},"OpenSearch"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"docker pull opensearchproject/opensearch:latest\n")),(0,a.kt)("h4",{id:"opensearch-dashboard"},"OpenSearch Dashboard"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"docker pull opensearchproject/opensearch-dashboards:latest\n")),(0,a.kt)("h3",{id:"start-opensearch-containers"},"Start Opensearch Containers"),(0,a.kt)("h4",{id:"opensearch-1"},"OpenSearch"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" -e "plugins.security.disabled=true" opensearchproject/opensearch:latest \n')),(0,a.kt)("h4",{id:"opensearch-dashboard-1"},"OpenSearch Dashboard"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -it -d --network="host" -e "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true" opensearchproject/opensearch-dashboards:latest\n')),(0,a.kt)("h3",{id:"verify-if-the-containers-are-up--running"},"Verify if the containers are up & running"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Send a request to port 9200")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," curl http://127.0.0.1:9200\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"List Indices through curl ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},' curl -X GET "http://127.0.0.1:9200/_cat/indices?v"\n')),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Create Indices through Curl ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},' curl -X PUT "http://127.0.0.1:9200/your_index_name"\n')),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Delete Index ")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," curl --location --request DELETE 'http://127.0.0.1:9200/index_name'\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Fetch logs for an index_name")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," curl --location --request GET 'http://127.0.0.1:9200/ethereal/_search' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"query\": {\n \"match_all\": {}\n },\n \"size\": 10000\n }'\n")),(0,a.kt)("h3",{id:"enable-client-logging"},"Enable Client Logging"),(0,a.kt)("p",null,"Set VITE_FORCE_CLIENT_LOG_AGGREGATE to true to enable client log aggregation"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"VITE_FORCE_CLIENT_LOG_AGGREGATE=true\n")),(0,a.kt)("h3",{id:"enable-server-logging"},"Enable Server Logging"),(0,a.kt)("p",null,"Set DISABLE_SERVER_LOG=false to false to enable server log aggregation "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"DISABLE_SERVER_LOG=false\n \n")),(0,a.kt)("p",null,"Note: These changes in the ",(0,a.kt)("inlineCode",{parentName:"p"},".env.local")," file will ensure proper communication with OpenSearch and enable client and server log aggregation"))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/0991b023.73048e9e.js b/es/assets/js/0991b023.73048e9e.js new file mode 100644 index 000000000000..05b17f49f03b --- /dev/null +++ b/es/assets/js/0991b023.73048e9e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6524],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(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 a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={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,o=e.mdxType,c=e.originalType,s=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(r),f=o,m=u["".concat(s,".").concat(f)]||u[f]||d[f]||c;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=f;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:o,a[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>c,metadata:()=>i,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const c={},a="Concepts",i={unversionedId:"creator/concepts/readme",id:"creator/concepts/readme",title:"Concepts",description:"",source:"@site/docs/2_creator/1_concepts/readme.md",sourceDirName:"2_creator/1_concepts",slug:"/creator/concepts/",permalink:"/etherealengine-docs/es/docs/creator/concepts/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/1_concepts/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal for Creators",permalink:"/etherealengine-docs/es/docs/creator/"},next:{title:"Studio & Locations",permalink:"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations"}},s={},p=[],l={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"concepts"},"Concepts"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/0f5dde8f.b39c071a.js b/es/assets/js/0f5dde8f.b39c071a.js new file mode 100644 index 000000000000..b0970b5e2725 --- /dev/null +++ b/es/assets/js/0f5dde8f.b39c071a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3976],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>m});var r=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 l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function d(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var o=r.createContext({}),s=function(e){var t=r.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):d(d({},t),e)),a},c=function(e){var t=s(e.components);return r.createElement(o.Provider,{value:t},e.children)},v="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,o=e.parentName,c=n(e,["components","mdxType","originalType","parentName"]),v=s(a),h=i,m=v["".concat(o,".").concat(h)]||v[h]||u[h]||l;return a?r.createElement(m,d(d({ref:t},c),{},{components:a})):r.createElement(m,d({ref:t},c))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,d=new Array(l);d[0]=h;var n={};for(var o in t)hasOwnProperty.call(t,o)&&(n[o]=t[o]);n.originalType=e,n[v]="string"==typeof e?e:i,d[1]=n;for(var s=2;s{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>d,default:()=>u,frontMatter:()=>l,metadata:()=>n,toc:()=>s});var r=a(7462),i=(a(7294),a(3905));const l={},d="Ethereal Engine Admin Panel Guide",n={unversionedId:"host/Admin_Dashboard/readme",id:"host/Admin_Dashboard/readme",title:"Ethereal Engine Admin Panel Guide",description:"Dashboard",source:"@site/docs/1_host/3_Admin_Dashboard/readme.md",sourceDirName:"1_host/3_Admin_Dashboard",slug:"/host/Admin_Dashboard/",permalink:"/etherealengine-docs/es/docs/host/Admin_Dashboard/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/3_Admin_Dashboard/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Getting Started",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started"},next:{title:"Ethereal for Creators",permalink:"/etherealengine-docs/es/docs/creator/"}},o={},s=[{value:"Dashboard",id:"dashboard",level:2},{value:"Usage Dashboard",id:"usage-dashboard",level:3},{value:"Usage Time Series",id:"usage-time-series",level:3},{value:"Projects",id:"projects",level:2},{value:"Managing Projects",id:"managing-projects",level:3},{value:"Project Table",id:"project-table",level:3},{value:"Name",id:"name",level:4},{value:"Version",id:"version",level:4},{value:"Commit SHA",id:"commit-sha",level:4},{value:"Commit Date",id:"commit-date",level:4},{value:"Update",id:"update",level:4},{value:"GitHub Integration",id:"github-integration",level:4},{value:"User Access",id:"user-access",level:4},{value:"Invalidate Cache",id:"invalidate-cache",level:4},{value:"View Project Files",id:"view-project-files",level:4},{value:"Routes",id:"routes",level:2},{value:"Location",id:"location",level:2},{value:"Create Location",id:"create-location",level:3},{value:"Name",id:"name-1",level:4},{value:"Max Users",id:"max-users",level:4},{value:"Scene",id:"scene",level:4},{value:"Type",id:"type",level:4},{value:"Media Toggles",id:"media-toggles",level:4},{value:"Make Lobby",id:"make-lobby",level:4},{value:"Featured",id:"featured",level:4},{value:"Location Table",id:"location-table",level:3},{value:"Instance",id:"instance",level:2},{value:"Patch InstanceServer",id:"patch-instanceserver",level:3},{value:"Instance Table",id:"instance-table",level:3},{value:"Instance Table Actions",id:"instance-table-actions",level:3},{value:"Users",id:"users",level:2},{value:"Create User",id:"create-user",level:3},{value:"Name",id:"name-2",level:4},{value:"Avatar",id:"avatar",level:4},{value:"Scopes",id:"scopes",level:4},{value:"Admin:Admin",id:"adminadmin",level:5},{value:"Benchmarking:read/write",id:"benchmarkingreadwrite",level:5},{value:"Bot:read/write",id:"botreadwrite",level:5},{value:"contentPacks:read/write",id:"contentpacksreadwrite",level:5},{value:"Editor:write",id:"editorwrite",level:5},{value:"globalAvatars:read/write",id:"globalavatarsreadwrite",level:5},{value:"Groups:read/write",id:"groupsreadwrite",level:5},{value:"Instance:read/write",id:"instancereadwrite",level:5},{value:"Invite:read",id:"inviteread",level:5},{value:"Location:read/write",id:"locationreadwrite",level:5},{value:"Party:read/write",id:"partyreadwrite",level:5},{value:"Projects:read/write",id:"projectsreadwrite",level:5},{value:"realityPacks:read/write",id:"realitypacksreadwrite",level:5},{value:"Recording:read/write",id:"recordingreadwrite",level:5},{value:"Routes:read/write",id:"routesreadwrite",level:5},{value:"Scene:read/write",id:"scenereadwrite",level:5},{value:"Server:read/write",id:"serverreadwrite",level:5},{value:"Settings:read/write",id:"settingsreadwrite",level:5},{value:"Static_resource:read/write",id:"static_resourcereadwrite",level:5},{value:"User:read/write",id:"userreadwrite",level:5},{value:"User Table",id:"user-table",level:3},{value:"Invites",id:"invites",level:2},{value:"Avatar",id:"avatar-1",level:2},{value:"Create Avatar",id:"create-avatar",level:3},{value:"Avatar Name",id:"avatar-name",level:4},{value:"File Source",id:"file-source",level:4},{value:"Avatar Thumbnail",id:"avatar-thumbnail",level:4},{value:"Avatar Table",id:"avatar-table",level:3},{value:"Resources",id:"resources",level:2},{value:"Create Resource",id:"create-resource",level:3},{value:"Name",id:"name-3",level:4},{value:"Project",id:"project",level:4},{value:"File Source",id:"file-source-1",level:4},{value:"Benchmarking",id:"benchmarking",level:2},{value:"Bots",id:"bots",level:2}],c={toc:s},v="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(v,(0,r.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"ethereal-engine-admin-panel-guide"},"Ethereal Engine Admin Panel Guide"),(0,i.kt)("h2",{id:"dashboard"},"Dashboard"),(0,i.kt)("h3",{id:"usage-dashboard"},"Usage Dashboard"),(0,i.kt)("h3",{id:"usage-time-series"},"Usage Time Series"),(0,i.kt)("h2",{id:"projects"},"Projects"),(0,i.kt)("h3",{id:"managing-projects"},"Managing Projects"),(0,i.kt)("h3",{id:"project-table"},"Project Table"),(0,i.kt)("h4",{id:"name"},"Name"),(0,i.kt)("h4",{id:"version"},"Version"),(0,i.kt)("h4",{id:"commit-sha"},"Commit SHA"),(0,i.kt)("h4",{id:"commit-date"},"Commit Date"),(0,i.kt)("h4",{id:"update"},"Update"),(0,i.kt)("h4",{id:"github-integration"},"GitHub Integration"),(0,i.kt)("h4",{id:"user-access"},"User Access"),(0,i.kt)("h4",{id:"invalidate-cache"},"Invalidate Cache"),(0,i.kt)("h4",{id:"view-project-files"},"View Project Files"),(0,i.kt)("h2",{id:"routes"},"Routes"),(0,i.kt)("h2",{id:"location"},"Location"),(0,i.kt)("h3",{id:"create-location"},"Create Location"),(0,i.kt)("h4",{id:"name-1"},"Name"),(0,i.kt)("h4",{id:"max-users"},"Max Users"),(0,i.kt)("h4",{id:"scene"},"Scene"),(0,i.kt)("h4",{id:"type"},"Type"),(0,i.kt)("h4",{id:"media-toggles"},"Media Toggles"),(0,i.kt)("h4",{id:"make-lobby"},"Make Lobby"),(0,i.kt)("h4",{id:"featured"},"Featured"),(0,i.kt)("h3",{id:"location-table"},"Location Table"),(0,i.kt)("h2",{id:"instance"},"Instance"),(0,i.kt)("h3",{id:"patch-instanceserver"},"Patch InstanceServer"),(0,i.kt)("h3",{id:"instance-table"},"Instance Table"),(0,i.kt)("h3",{id:"instance-table-actions"},"Instance Table Actions"),(0,i.kt)("h2",{id:"users"},"Users"),(0,i.kt)("h3",{id:"create-user"},"Create User"),(0,i.kt)("h4",{id:"name-2"},"Name"),(0,i.kt)("h4",{id:"avatar"},"Avatar"),(0,i.kt)("h4",{id:"scopes"},"Scopes"),(0,i.kt)("h5",{id:"adminadmin"},"Admin:Admin"),(0,i.kt)("h5",{id:"benchmarkingreadwrite"},"Benchmarking:read/write"),(0,i.kt)("h5",{id:"botreadwrite"},"Bot:read/write"),(0,i.kt)("h5",{id:"contentpacksreadwrite"},"contentPacks:read/write"),(0,i.kt)("h5",{id:"editorwrite"},"Editor:write"),(0,i.kt)("h5",{id:"globalavatarsreadwrite"},"globalAvatars:read/write"),(0,i.kt)("h5",{id:"groupsreadwrite"},"Groups:read/write"),(0,i.kt)("h5",{id:"instancereadwrite"},"Instance:read/write"),(0,i.kt)("h5",{id:"inviteread"},"Invite:read"),(0,i.kt)("h5",{id:"locationreadwrite"},"Location:read/write"),(0,i.kt)("h5",{id:"partyreadwrite"},"Party:read/write"),(0,i.kt)("h5",{id:"projectsreadwrite"},"Projects:read/write"),(0,i.kt)("h5",{id:"realitypacksreadwrite"},"realityPacks:read/write"),(0,i.kt)("h5",{id:"recordingreadwrite"},"Recording:read/write"),(0,i.kt)("h5",{id:"routesreadwrite"},"Routes:read/write"),(0,i.kt)("h5",{id:"scenereadwrite"},"Scene:read/write"),(0,i.kt)("h5",{id:"serverreadwrite"},"Server:read/write"),(0,i.kt)("h5",{id:"settingsreadwrite"},"Settings:read/write"),(0,i.kt)("h5",{id:"static_resourcereadwrite"},"Static_resource:read/write"),(0,i.kt)("h5",{id:"userreadwrite"},"User:read/write"),(0,i.kt)("h3",{id:"user-table"},"User Table"),(0,i.kt)("h2",{id:"invites"},"Invites"),(0,i.kt)("h2",{id:"avatar-1"},"Avatar"),(0,i.kt)("h3",{id:"create-avatar"},"Create Avatar"),(0,i.kt)("h4",{id:"avatar-name"},"Avatar Name"),(0,i.kt)("h4",{id:"file-source"},"File Source"),(0,i.kt)("h4",{id:"avatar-thumbnail"},"Avatar Thumbnail"),(0,i.kt)("h3",{id:"avatar-table"},"Avatar Table"),(0,i.kt)("h2",{id:"resources"},"Resources"),(0,i.kt)("h3",{id:"create-resource"},"Create Resource"),(0,i.kt)("h4",{id:"name-3"},"Name"),(0,i.kt)("h4",{id:"project"},"Project"),(0,i.kt)("h4",{id:"file-source-1"},"File Source"),(0,i.kt)("h2",{id:"benchmarking"},"Benchmarking"),(0,i.kt)("p",null,"In work"),(0,i.kt)("h2",{id:"bots"},"Bots"),(0,i.kt)("p",null,"In work"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/12905b1d.d62b8bd9.js b/es/assets/js/12905b1d.d62b8bd9.js new file mode 100644 index 000000000000..5aae94537557 --- /dev/null +++ b/es/assets/js/12905b1d.d62b8bd9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2345],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});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({}),h=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=h(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=h(n),d=o,g=p["".concat(l,".").concat(d)]||p[d]||c[d]||i;return n?a.createElement(g,r(r({ref:t},u),{},{components:n})):a.createElement(g,r({ref:t},u))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[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:o,r[1]=s;for(var h=2;h{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>h});var a=n(7462),o=(n(7294),n(3905));const i={},r="How to set up GitHub to install external projects",s={unversionedId:"host/devops_deployment/setup_github_oauth_for_projects",id:"host/devops_deployment/setup_github_oauth_for_projects",title:"How to set up GitHub to install external projects",description:"Ethereal Engine is extensible via Projects, which can contain",source:"@site/docs/1_host/2_devops_deployment/4_setup_github_oauth_for_projects.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/setup_github_oauth_for_projects",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/4_setup_github_oauth_for_projects.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Database Migrations",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations"},next:{title:"Cluster Management",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes"}},l={},h=[{value:"Create a GitHub OAuth App in an organization, or your user",id:"create-a-github-oauth-app-in-an-organization-or-your-user",level:2},{value:"Create client secret, note Client ID",id:"create-client-secret-note-client-id",level:2},{value:"Make note of Client ID",id:"make-note-of-client-id",level:3},{value:"Generate client secret",id:"generate-client-secret",level:3},{value:"Configure Ethereal Engine deployment with IDs/keys",id:"configure-ethereal-engine-deployment-with-idskeys",level:2},{value:"Pre-initial installation",id:"pre-initial-installation",level:3},{value:"Post-installation, if you have another authentication method configured",id:"post-installation-if-you-have-another-authentication-method-configured",level:3},{value:"Post-installation, if you do not have any authentication method configured",id:"post-installation-if-you-do-not-have-any-authentication-method-configured",level:3},{value:"Setting up GitHub webhook",id:"setting-up-github-webhook",level:2}],u={toc:h},p="wrapper";function c(e){let{components:t,...i}=e;return(0,o.kt)(p,(0,a.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"how-to-set-up-github-to-install-external-projects"},"How to set up GitHub to install external projects"),(0,o.kt)("p",null,"Ethereal Engine is extensible via ",(0,o.kt)("a",{parentName:"p",href:"../3_concepts/1_projects_api.md"},"Projects"),", which can contain\nnew scenes, new avatars, new static resources, additional code, and more. Ethereal Engine integrates\nwith GitHub to push and pull projects for backup and restoration, and one can also install existing\nprojects from GitHub. In order to install projects from private repositories, or to push local project\nchanges to a GitHub repo, an OAuth app from GitHub (not a GitHub app, that is something different) needs to be\ncreated, and the logged-in user must be connected in Ethereal Engine to GitHub (i.e. must have logged in via\nGitHub at some point) and have permission to access the source and destination repositories."),(0,o.kt)("p",null,"Note that it is recommended that you complete most of this before the initial installation of\nyour deployment, so that you can log in via GitHub and be granted admin status as the first\nlogged-in user. If you do not, then you will either need to manually insert some of these values\ninto the database so that you can log yourself in; have another log method configured already\nand use that logged-in admin user; or reset the database with these values configured in the\nupdated Helm configuration that is used for the reset."),(0,o.kt)("h2",{id:"create-a-github-oauth-app-in-an-organization-or-your-user"},"Create a GitHub OAuth App in an organization, or your user"),(0,o.kt)("p",null,"You can either create an OAuth App for your personal GitHub account or for an organization that\nyou have sufficient permissions on. Either will work for this setup."),(0,o.kt)("p",null,"The general instructions for doing this can be found ",(0,o.kt)("a",{parentName:"p",href:"https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app"},"here"),".\nThe specifics you'll need to enter are as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Application name: Anything you want"),(0,o.kt)("li",{parentName:"ul"},"Homepage URL: Whatever you want, this is just what is linked to from the OAuth authorization page"),(0,o.kt)("li",{parentName:"ul"},"Authorization callback URL: enter ",(0,o.kt)("inlineCode",{parentName:"li"},"https://api./oauth/github/callback"),", e.g. ",(0,o.kt)("inlineCode",{parentName:"li"},"https://api.example.com/oauth/github/callback"),". ^ "),(0,o.kt)("li",{parentName:"ul"},"Enable Device Flow: Leave unchecked")),(0,o.kt)("p",null,"^If you are running this locally off of localhost, this should be ",(0,o.kt)("inlineCode",{parentName:"p"},"https://localhost:3030/oauth/github/callback"),".\nIf you are using an explicit IP address instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"localhost"),", then use that IP address here, but keep the ",(0,o.kt)("inlineCode",{parentName:"p"},":3030"),",\nas that is the port that the API server runs on, and GitHub needs to call back to the API server."),(0,o.kt)("h2",{id:"create-client-secret-note-client-id"},"Create client secret, note Client ID"),(0,o.kt)("p",null,"Once the app has been created, you will be redirected to the General settings for it.\nHere, you will generate one credential for the app, so that your deployment can be authenticated."),(0,o.kt)("h3",{id:"make-note-of-client-id"},"Make note of Client ID"),(0,o.kt)("p",null,"Near the top of this page is the Client ID for the app. This is a public ID for the app.\nIt will be used when configuring Ethereal Engine."),(0,o.kt)("h3",{id:"generate-client-secret"},"Generate client secret"),(0,o.kt)("p",null,"Below ",(0,o.kt)("inlineCode",{parentName:"p"},"Client ID")," is a section ",(0,o.kt)("inlineCode",{parentName:"p"},"Client secrets"),". None are created by default, so click the\nbutton ",(0,o.kt)("inlineCode",{parentName:"p"},"Generate a new client secret"),". As the notifications that appear say, you will only see the\nfull secret right now, so copy it somewhere retrievable (but not anywhere publicly accessible). If\nyou ever lose the secret, you can always generate a new one."),(0,o.kt)("h2",{id:"configure-ethereal-engine-deployment-with-idskeys"},"Configure Ethereal Engine deployment with IDs/keys"),(0,o.kt)("h3",{id:"pre-initial-installation"},"Pre-initial installation"),(0,o.kt)("p",null,"If you have not done the initial installation/deployment yet, then you can add most of the values\nabove to the Helm configuration, and they will be inserted into the database so that GitHub login\nis enabled from the start, and you can then log in via GitHub and be granted admin status."),(0,o.kt)("p",null,"Enter the Client ID for ",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT_ID"),", and the Client secret for\n",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT SECRET")," in the section ",(0,o.kt)("inlineCode",{parentName:"p"},"api.extraEnv"),". It is advised that you enclose all of these in\ndouble quotes in the .yaml file, so that they are interpreted as strings even if they start with a\nnumber, e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},'GITHUB_CLIENT_ID: "17592577832789234"')," If you see ",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_APP_ID"),", it is not used;\nit is left over from a prior implementation of GitHub Apps, which no longer works."),(0,o.kt)("p",null,"Continue with the setup instructions. When you run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install")," with your configuration file, the\nGitHub credentials will be included."),(0,o.kt)("h3",{id:"post-installation-if-you-have-another-authentication-method-configured"},"Post-installation, if you have another authentication method configured"),(0,o.kt)("p",null,"If you have already installed the platform but configured it with another login method, such as\nemail or another OAuth provider, then log in as an admin user. If you haven't logged in with anything\nyet, then the first user that logs in will be made an admin."),(0,o.kt)("p",null,"Go to ",(0,o.kt)("inlineCode",{parentName:"p"},"/admin/settings"),". Click on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Authentication")," selector. A page should open with a\nsection ",(0,o.kt)("inlineCode",{parentName:"p"},"OAuth")," that takes up the bottom two-thirds. Under ",(0,o.kt)("inlineCode",{parentName:"p"},"GitHub"),", enter\nthe Client ID under ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," and the Client Secret under ",(0,o.kt)("inlineCode",{parentName:"p"},"Secret"),". Click the Save button at the bottom."),(0,o.kt)("h3",{id:"post-installation-if-you-do-not-have-any-authentication-method-configured"},"Post-installation, if you do not have any authentication method configured"),(0,o.kt)("p",null,"If you have already set up the platform but did not configure any authentication method,\nthen you are in a bit of a bind where you can't log in to get admin privileges, but need admin\nprivileges to configure an authentication method. The way around this is to reset the database\nand provide the GitHub credentials as part of this process - this is similar to what would happen\non initial installation. Note that this will erase anything you've done so far, but without any\nadmins, the most you'd have been likely to do is change some guest users' avatars."),(0,o.kt)("p",null,"Open your Helm configuration. Enter the Client ID for ",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT_ID")," and the Client secret for\n",(0,o.kt)("inlineCode",{parentName:"p"},"GITHUB_CLIENT SECRET")," in the section ",(0,o.kt)("inlineCode",{parentName:"p"},"api.extraEnv"),". It is advised that you enclose all of these in\ndouble quotes in the .yaml file, so that they are interpreted as strings even if they start with a\nnumber, e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},'GITHUB_CLIENT_ID: "17592577832789234"')),(0,o.kt)("p",null,"Next, run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f --set-string api.extraEnv.FORCE_DB_REFRESH=true etherealengine/etherealengine"),".\nThis tells Helm to restart the API servers, and for them to wipe the database and reseed it with the values\nin the configuration file. It should only take a minute or two, and you should then run\n",(0,o.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values --set-string api.extraEnv.FORCE_DB_REFRESH=false etherealengine/etherealengine")," to unset\nthe flag telling it to reset the database."),(0,o.kt)("p",null,"Once this is done, you should be able to log in with GitHub and be granted admin status."),(0,o.kt)("h1",{id:"logging-in-with-github-and-granting-access-to-other-organizations"},"Logging in with GitHub and Granting Access to Other Organizations"),(0,o.kt)("p",null,"When you log in with GitHub, you will be asked to grant access to your user information as well as the repositories\nthat the OAuth app has authorized for. Ethereal Engine will have access to your personal repositories and,\nif the OAuth app was created in a GitHub organization, all repositories in that organization. It will not\nhave inherent push access to other organizations' repositories or pull access to their private repositories."),(0,o.kt)("p",null,"There are two ways to grant access to other repositories. When you are first signing in via GitHub and are\npresented with the screen to authorize the OAuth app's permissions, you should see a section near the bottom\nthat shows all of the organizations you are in. If you have admin rights to that organization, you can Grant\naccess. If you do not have admin rights, then you can Request access, and someone who does have admin rights\nwill have to approve it."),(0,o.kt)("p",null,(0,o.kt)("img",{src:n(1413).Z,width:"638",height:"1162"})),(0,o.kt)("p",null,"If you have already gone through the OAuth approval page, it will not be shown again - all subsequent logins\nwill bypass this page",(0,o.kt)("sup",{parentName:"p",id:"fnref-1"},(0,o.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),". In order to grant the OAuth app access to other organizations, follow\n",(0,o.kt)("a",{parentName:"p",href:"https://docs.github.com/en/organizations/managing-oauth-access-to-your-organizations-data/approving-oauth-apps-for-your-organization"},"these steps")),(0,o.kt)("p",null,"In short form:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Go to (",(0,o.kt)("a",{parentName:"li",href:"https://github.com/settings/applications"},"https://github.com/settings/applications"),")"),(0,o.kt)("li",{parentName:"ol"},"Click on the name of the OAuth app installed in Ethereal Engine"),(0,o.kt)("li",{parentName:"ol"},"Under ",(0,o.kt)("inlineCode",{parentName:"li"},"Organization access"),", click on Grant/Request for the organizations you want Ethereal Engine to\nhave access to")),(0,o.kt)("h1",{id:"installing-ethereal-engine-projects-from-github"},"Installing Ethereal Engine projects from GitHub"),(0,o.kt)("p",null,"See ",(0,o.kt)("a",{parentName:"p",href:"../3_concepts/1_projects_api.md"},"the section 'Graphical Install Flow")," for more information on how to install\nprojects from GitHub."),(0,o.kt)("h1",{id:"user-repo-access-to-github-with-optional-webhooks"},"User Repo Access to GitHub (with optional webhooks)"),(0,o.kt)("p",null,"Users can push projects to GitHub if they have write/maintain/admin access to the associated GitHub repository.\nSince fetching this access from the GitHub API every time a user fetches their projects can take a noticeable\namount of time, Ethereal Engine stores users' GitHub repo access in its database. This is much faster to access."),(0,o.kt)("p",null,"There are multiple actions that will make the engine re-fetch and update users' repo access:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"When a user logs in via GitHub"),(0,o.kt)("li",{parentName:"ul"},'When a user clicks on the button "Refresh GitHub Repo Access" on /admin/projects or /studio (must be logged\nin as a user that is associated with a GitHub account)'),(0,o.kt)("li",{parentName:"ul"},"Via a GitHub webhook - must manually configure this")),(0,o.kt)("h2",{id:"setting-up-github-webhook"},"Setting up GitHub webhook"),(0,o.kt)("p",null,"Ethereal Engine currently only supports webhook notifications for Collaborators being added/edited/removed.\nChanges in Teams are not handled by Ethereal Engine due to the opacity of team members. (Team change webhooks do not\ninclude team members, and the engine does not track who is in a team)"),(0,o.kt)("p",null,"An admin needs to go to /admin/settings, click on 'Server', then enter a secret key in the field\n\"GitHub Webhook Secret\", then click the Save button. The secret can be any string you make up.\nRandomly generated strings are encouraged."),(0,o.kt)("p",null,'Next, go to GitGub. In the Repository or Organization that you want to send updates for, go to\nSettings -> Code(, planning,) and automation -> Webhooks, then click "Add webhook".'),(0,o.kt)("p",null,"For Payload URL, enter ",(0,o.kt)("inlineCode",{parentName:"p"},"/github-repo-access-webhook"),", e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"https://api.example.com/github-repo-access-webhook"),"\nSet Content Type to ",(0,o.kt)("inlineCode",{parentName:"p"},"application/json"),'. For Secret, enter the secret from the earlier step. For\n"Which events would you like to trigger this webhook?", select "Let me select individual events."\nIn the list of events that appears, uncheck "Pushes", anf check "Collaborator add, remove, or changed".\nAt the very bottom of the page, click the green button "Add webhook".'),(0,o.kt)("p",null,'After the webhook is created, the webhook will send a ping request to the API endpoint you provided. If the URL\nwas entered correctly, and the secret was entered correctly in both ends, the ping should get a 200 response.\nYou can check the status under the "Recent Deliveries" tab of that webhook on GitHub.'),(0,o.kt)("p",null,"When this is working, whenever a user is added, removed, or has their access modified, the engine\nwill re-fetch the user's full set of GitHub repo accesses and update the database's records."))}c.isMDXComponent=!0},1413:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/oauth-login-screen-544efd6284a12360ec3f7e1498a8a48a.png"}}]); \ No newline at end of file diff --git a/es/assets/js/1426.3913c64b.js b/es/assets/js/1426.3913c64b.js new file mode 100644 index 000000000000..7012afaaf04f --- /dev/null +++ b/es/assets/js/1426.3913c64b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1426],{1426:(e,t,r)=>{function n(e,t){var r=void 0;return function(){for(var n=arguments.length,o=new Array(n),i=0;ipn});var a=function(){};function c(e){var t=e.item,r=e.items;return{index:t.__autocomplete_indexName,items:[t],positions:[1+r.findIndex((function(e){return e.objectID===t.objectID}))],queryID:t.__autocomplete_queryID,algoliaSource:["autocomplete"]}}function l(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,a,c=[],l=!0,u=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;l=!1}else for(;!(l=(n=i.call(r)).done)&&(c.push(n.value),c.length!==t);l=!0);}catch(s){u=!0,o=s}finally{try{if(!l&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(u)throw o}}return c}}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return u(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return u(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function y(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 h(e){for(var t=1;t=3||2===r&&n>=4||1===r&&n>=10);function i(t,r,n){if(o&&void 0!==n){var i=n[0].__autocomplete_algoliaCredentials,a={"X-Algolia-Application-Id":i.appId,"X-Algolia-API-Key":i.apiKey};e.apply(void 0,[t].concat(p(r),[{headers:a}]))}else e.apply(void 0,[t].concat(p(r)))}return{init:function(t,r){e("init",{appId:t,apiKey:r})},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("clickedObjectIDsAfterSearch",g(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("clickedObjectIDs",g(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n0&&e.apply(void 0,["clickedFilters"].concat(r))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("convertedObjectIDsAfterSearch",g(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&i("convertedObjectIDs",g(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n0&&e.apply(void 0,["convertedFilters"].concat(r))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r0&&t.reduce((function(e,t){var r=t.items,n=d(t,f);return[].concat(p(e),p(function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,r=[],n=0;n0&&e.apply(void 0,["viewedFilters"].concat(r))}}}function S(e){var t=e.items.reduce((function(e,t){var r;return e[t.__autocomplete_indexName]=(null!==(r=e[t.__autocomplete_indexName])&&void 0!==r?r:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function j(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function w(e){return w="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},w(e)}function E(e){return function(e){if(Array.isArray(e))return P(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return P(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return P(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function P(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r0&&C({onItemsChange:o,items:r,insights:f,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,r=e.onSelect,n=e.onActive;s("addAlgoliaAgent","insights-plugin"),t({algoliaInsightsPlugin:{__algoliaSearchParameters:{clickAnalytics:!0},insights:f}}),r((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&l({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Selected"},c({item:t,items:m.current}))]})})),n((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&u({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Active"},c({item:t,items:m.current}))]})}))},onStateChange:function(e){var t=e.state;p({state:t})},__autocomplete_pluginOptions:e}}function N(e){return N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},N(e)}function T(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 q(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==N(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==N(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===N(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function R(e,t,r){var n,o=t.initialState;return{getState:function(){return o},dispatch:function(n,i){var a=function(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r0},reshape:function(e){return e.sources}},e),{},{id:null!==(r=e.id)&&void 0!==r?r:"autocomplete-".concat(V++),plugins:o,initialState:X({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var r;null===(r=e.onStateChange)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onStateChange)||void 0===r?void 0:r.call(e,t)}))},onSubmit:function(t){var r;null===(r=e.onSubmit)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onSubmit)||void 0===r?void 0:r.call(e,t)}))},onReset:function(t){var r;null===(r=e.onReset)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onReset)||void 0===r?void 0:r.call(e,t)}))},getSources:function(r){return Promise.all([].concat(Q(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var r=[];return Promise.resolve(e(t)).then((function(e){return Array.isArray(e),Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,r.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));r.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:a,onResolve:a};Object.keys(t).forEach((function(e){t[e].__default=!0}));var n=$($({},t),e);return Promise.resolve(n)})))}))}(e,r)}))).then((function(e){return L(e)})).then((function(e){return e.map((function(e){return X(X({},e),{},{onSelect:function(r){e.onSelect(r),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,r)}))},onActive:function(r){e.onActive(r),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,r)}))},onResolve:function(r){e.onResolve(r),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,r)}))}})}))}))},navigator:X({navigate:function(e){var t=e.itemUrl;n.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,r=n.open(t,"_blank","noopener");null==r||r.focus()},navigateNewWindow:function(e){var t=e.itemUrl;n.open(t,"_blank","noopener")}},e.navigator)})}function te(e){return te="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},te(e)}function re(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 ne(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Ie,De,Ae,ke=null,xe=(Ie=-1,De=-1,Ae=void 0,function(e){var t=++Ie;return Promise.resolve(e).then((function(e){return Ae&&t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Me=/((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i;function He(e){return He="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},He(e)}var Fe=["props","refresh","store"],Ue=["inputElement","formElement","panelElement"],Be=["inputElement"],Ve=["inputElement","maxLength"],Ke=["sourceIndex"],$e=["sourceIndex"],Je=["item","source","sourceIndex"];function ze(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 We(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ge(e){var t=e.props,r=e.refresh,n=e.store,o=Ze(e,Fe),i=function(e,t){return void 0!==t?"".concat(e,"-").concat(t):e};return{getEnvironmentProps:function(e){var r=e.inputElement,o=e.formElement,i=e.panelElement;function a(e){!n.getState().isOpen&&n.pendingRequests.isEmpty()||e.target===r||!1===[o,i].some((function(t){return r=t,n=e.target,r===n||r.contains(n);var r,n}))&&(n.dispatch("blur",null),t.debug||n.pendingRequests.cancelAll())}return We({onTouchStart:a,onMouseDown:a,onTouchMove:function(e){!1!==n.getState().isOpen&&r===t.environment.document.activeElement&&e.target!==r&&r.blur()}},Ze(e,Ue))},getRootProps:function(e){return We({role:"combobox","aria-expanded":n.getState().isOpen,"aria-haspopup":"listbox","aria-owns":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){e.inputElement;return We({action:"",noValidate:!0,role:"search",onSubmit:function(i){var a;i.preventDefault(),t.onSubmit(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("submit",null),null===(a=e.inputElement)||void 0===a||a.blur()},onReset:function(i){var a;i.preventDefault(),t.onReset(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("reset",null),null===(a=e.inputElement)||void 0===a||a.focus()}},Ze(e,Be))},getLabelProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,Ke);return We({htmlFor:"".concat(i(t.id,n),"-input"),id:"".concat(i(t.id,n),"-label")},o)},getInputProps:function(e){var i;function c(e){(t.openOnFocus||Boolean(n.getState().query))&&Ce(We({event:e,props:t,query:n.getState().completion||n.getState().query,refresh:r,store:n},o)),n.dispatch("focus",null)}var l=e||{},u=(l.inputElement,l.maxLength),s=void 0===u?512:u,f=Ze(l,Ve),m=ge(n.getState()),p=function(e){return Boolean(e&&e.match(Me))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),v=null!=m&&m.itemUrl&&!p?"go":"search";return We({"aria-autocomplete":"both","aria-activedescendant":n.getState().isOpen&&null!==n.getState().activeItemId?"".concat(t.id,"-item-").concat(n.getState().activeItemId):void 0,"aria-controls":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:n.getState().completion||n.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:v,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:s,type:"search",onChange:function(e){Ce(We({event:e,props:t,query:e.currentTarget.value.slice(0,s),refresh:r,store:n},o))},onKeyDown:function(e){!function(e){var t=e.event,r=e.props,n=e.refresh,o=e.store,i=Le(e,Ne);if("ArrowUp"===t.key||"ArrowDown"===t.key){var a=function(){var e=r.environment.document.getElementById("".concat(r.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},c=function(){var e=ge(o.getState());if(null!==o.getState().activeItemId&&e){var r=e.item,a=e.itemInputValue,c=e.itemUrl,l=e.source;l.onActive(qe({event:t,item:r,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(r.openOnFocus||Boolean(o.getState().query))?Ce(qe({event:t,props:r,query:o.getState().query,refresh:n,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:r.defaultActiveItemId}),c(),setTimeout(a,0)})):(o.dispatch(t.key,{}),c(),a())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(r.debug||o.pendingRequests.cancelAll());t.preventDefault();var l=ge(o.getState()),u=l.item,s=l.itemInputValue,f=l.itemUrl,m=l.source;if(t.metaKey||t.ctrlKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewTab({itemUrl:f,item:u,state:o.getState()}));else if(t.shiftKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewWindow({itemUrl:f,item:u,state:o.getState()}));else if(t.altKey);else{if(void 0!==f)return m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),void r.navigator.navigate({itemUrl:f,item:u,state:o.getState()});Ce(qe({event:t,nextState:{isOpen:!1},props:r,query:s,refresh:n,store:o},i)).then((function(){m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i))}))}}}(We({event:e,props:t,refresh:r,store:n},o))},onFocus:c,onBlur:a,onClick:function(r){e.inputElement!==t.environment.document.activeElement||n.getState().isOpen||c(r)}},f)},getPanelProps:function(e){return We({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){n.dispatch("mouseleave",null)}},e)},getListProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,$e);return We({role:"listbox","aria-labelledby":"".concat(i(t.id,n),"-label"),id:"".concat(i(t.id,n),"-list")},o)},getItemProps:function(e){var a=e.item,c=e.source,l=e.sourceIndex,u=Ze(e,Je);return We({id:"".concat(i(t.id,l),"-item-").concat(a.__autocomplete_id),role:"option","aria-selected":n.getState().activeItemId===a.__autocomplete_id,onMouseMove:function(e){if(a.__autocomplete_id!==n.getState().activeItemId){n.dispatch("mousemove",a.__autocomplete_id);var t=ge(n.getState());if(null!==n.getState().activeItemId&&t){var i=t.item,c=t.itemInputValue,l=t.itemUrl,u=t.source;u.onActive(We({event:e,item:i,itemInputValue:c,itemUrl:l,refresh:r,source:u,state:n.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var i=c.getItemInputValue({item:a,state:n.getState()}),l=c.getItemUrl({item:a,state:n.getState()});(l?Promise.resolve():Ce(We({event:e,nextState:{isOpen:!1},props:t,query:i,refresh:r,store:n},o))).then((function(){c.onSelect(We({event:e,item:a,itemInputValue:i,itemUrl:l,refresh:r,source:c,state:n.getState()},o))}))}},u)}}}var Xe=[{segment:"autocomplete-core",version:"1.9.3"}];function Ye(e){return Ye="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ye(e)}function et(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 tt(e){for(var t=1;t=r?null===n?null:0:o}function at(e){return at="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},at(e)}function ct(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 lt(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function kt(e){var t=e.translations,r=void 0===t?{}:t,n=At(e,Pt),o=r.noResultsText,i=void 0===o?"No results for":o,a=r.suggestedQueryText,c=void 0===a?"Try searching for":a,l=r.reportMissingResultsText,u=void 0===l?"Believe this query should return results?":l,s=r.reportMissingResultsLinkText,f=void 0===s?"Let us know.":s,m=n.state.context.searchSuggestions;return yt.createElement("div",{className:"DocSearch-NoResults"},yt.createElement("div",{className:"DocSearch-Screen-Icon"},yt.createElement(Et,null)),yt.createElement("p",{className:"DocSearch-Title"},i,' "',yt.createElement("strong",null,n.state.query),'"'),m&&m.length>0&&yt.createElement("div",{className:"DocSearch-NoResults-Prefill-List"},yt.createElement("p",{className:"DocSearch-Help"},c,":"),yt.createElement("ul",null,m.slice(0,3).reduce((function(e,t){return[].concat(It(e),[yt.createElement("li",{key:t},yt.createElement("button",{className:"DocSearch-Prefill",key:t,type:"button",onClick:function(){n.setQuery(t.toLowerCase()+" "),n.refresh(),n.inputRef.current.focus()}},t))])}),[]))),n.getMissingResultsUrl&&yt.createElement("p",{className:"DocSearch-Help"},"".concat(u," "),yt.createElement("a",{href:n.getMissingResultsUrl({query:n.state.query}),target:"_blank",rel:"noopener noreferrer"},f)))}var xt=function(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))};function Ct(e){switch(e.type){case"lvl1":return yt.createElement(xt,null);case"content":return yt.createElement(Nt,null);default:return yt.createElement(_t,null)}}function _t(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}function Nt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 5H3h14zm0 5H3h14zm0 5H3h14z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function Tt(){return yt.createElement("svg",{className:"DocSearch-Hit-Select-Icon",width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M18 3v4c0 2-2 4-4 4H2"}),yt.createElement("path",{d:"M8 17l-6-6 6-6"})))}var qt=["hit","attribute","tagName"];function Rt(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 Lt(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ft(e,t){return t.split(".").reduce((function(e,t){return null!=e&&e[t]?e[t]:null}),e)}function Ut(e){var t=e.hit,r=e.attribute,n=e.tagName,o=void 0===n?"span":n,i=Ht(e,qt);return(0,yt.createElement)(o,Lt(Lt({},i),{},{dangerouslySetInnerHTML:{__html:Ft(t,"_snippetResult.".concat(r,".value"))||Ft(t,r)}}))}function Bt(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==r)return;var n,o,i=[],a=!0,c=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(l){c=!0,o=l}finally{try{a||null==r.return||r.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Vt(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Vt(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vt(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r|<\/mark>)/g,Wt=RegExp(zt.source);function Qt(e){var t,r,n=e;if(!n.__docsearch_parent&&!e._highlightResult)return e.hierarchy.lvl0;var o=((n.__docsearch_parent?null===(t=n.__docsearch_parent)||void 0===t||null===(t=t._highlightResult)||void 0===t||null===(t=t.hierarchy)||void 0===t?void 0:t.lvl0:null===(r=e._highlightResult)||void 0===r||null===(r=r.hierarchy)||void 0===r?void 0:r.lvl0)||{}).value;return o&&Wt.test(o)?o.replace(zt,""):o}function Zt(){return Zt=Object.assign||function(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function or(e){var t=e.translations,r=void 0===t?{}:t,n=nr(e,tr),o=r.recentSearchesTitle,i=void 0===o?"Recent":o,a=r.noRecentSearchesText,c=void 0===a?"No recent searches":a,l=r.saveRecentSearchButtonTitle,u=void 0===l?"Save this search":l,s=r.removeRecentSearchButtonTitle,f=void 0===s?"Remove this search from history":s,m=r.favoriteSearchesTitle,p=void 0===m?"Favorite":m,v=r.removeFavoriteSearchButtonTitle,d=void 0===v?"Remove this search from favorites":v;return"idle"===n.state.status&&!1===n.hasCollections?n.disableUserPersonalization?null:yt.createElement("div",{className:"DocSearch-StartScreen"},yt.createElement("p",{className:"DocSearch-Help"},c)):!1===n.hasCollections?null:yt.createElement("div",{className:"DocSearch-Dropdown-Container"},yt.createElement($t,rr({},n,{title:i,collection:n.state.collections[0],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Xt,null))},renderAction:function(e){var t=e.item,r=e.runFavoriteTransition,o=e.runDeleteTransition;return yt.createElement(yt.Fragment,null,yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:u,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.add(t),n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(Yt,null))),yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:f,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),o((function(){n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(er,null))))}})),yt.createElement($t,rr({},n,{title:p,collection:n.state.collections[1],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Yt,null))},renderAction:function(e){var t=e.item,r=e.runDeleteTransition;return yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:d,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.remove(t),n.refresh()}))}},yt.createElement(er,null)))}})))}var ir=["translations"];function ar(){return ar=Object.assign||function(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var lr=yt.memo((function(e){var t=e.translations,r=void 0===t?{}:t,n=cr(e,ir);if("error"===n.state.status)return yt.createElement(wt,{translations:null==r?void 0:r.errorScreen});var o=n.state.collections.some((function(e){return e.items.length>0}));return n.state.query?!1===o?yt.createElement(kt,ar({},n,{translations:null==r?void 0:r.noResultsScreen})):yt.createElement(Gt,n):yt.createElement(or,ar({},n,{hasCollections:o,translations:null==r?void 0:r.startScreen}))}),(function(e,t){return"loading"===t.state.status||"stalled"===t.state.status}));function ur(){return yt.createElement("svg",{viewBox:"0 0 38 38",stroke:"currentColor",strokeOpacity:".5"},yt.createElement("g",{fill:"none",fillRule:"evenodd"},yt.createElement("g",{transform:"translate(1 1)",strokeWidth:"2"},yt.createElement("circle",{strokeOpacity:".3",cx:"18",cy:"18",r:"18"}),yt.createElement("path",{d:"M36 18c0-9.94-8.06-18-18-18"},yt.createElement("animateTransform",{attributeName:"transform",type:"rotate",from:"0 18 18",to:"360 18 18",dur:"1s",repeatCount:"indefinite"})))))}var sr=r(830),fr=["translations"];function mr(){return mr=Object.assign||function(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function vr(e){var t=e.translations,r=void 0===t?{}:t,n=pr(e,fr),o=r.resetButtonTitle,i=void 0===o?"Clear the query":o,a=r.resetButtonAriaLabel,c=void 0===a?"Clear the query":a,l=r.cancelButtonText,u=void 0===l?"Cancel":l,s=r.cancelButtonAriaLabel,f=void 0===s?"Cancel":s,m=n.getFormProps({inputElement:n.inputRef.current}).onReset;return yt.useEffect((function(){n.autoFocus&&n.inputRef.current&&n.inputRef.current.focus()}),[n.autoFocus,n.inputRef]),yt.useEffect((function(){n.isFromSelection&&n.inputRef.current&&n.inputRef.current.select()}),[n.isFromSelection,n.inputRef]),yt.createElement(yt.Fragment,null,yt.createElement("form",{className:"DocSearch-Form",onSubmit:function(e){e.preventDefault()},onReset:m},yt.createElement("label",mr({className:"DocSearch-MagnifierLabel"},n.getLabelProps()),yt.createElement(sr.W,null)),yt.createElement("div",{className:"DocSearch-LoadingIndicator"},yt.createElement(ur,null)),yt.createElement("input",mr({className:"DocSearch-Input",ref:n.inputRef},n.getInputProps({inputElement:n.inputRef.current,autoFocus:n.autoFocus,maxLength:ht}))),yt.createElement("button",{type:"reset",title:i,className:"DocSearch-Reset","aria-label":c,hidden:!n.state.query},yt.createElement(er,null))),yt.createElement("button",{className:"DocSearch-Cancel",type:"reset","aria-label":f,onClick:n.onClose},u))}var dr=["_highlightResult","_snippetResult"];function yr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function hr(e){return!1===function(){var e="__TEST_KEY__";try{return localStorage.setItem(e,""),localStorage.removeItem(e),!0}catch(t){return!1}}()?{setItem:function(){},getItem:function(){return[]}}:{setItem:function(t){return window.localStorage.setItem(e,JSON.stringify(t))},getItem:function(){var t=window.localStorage.getItem(e);return t?JSON.parse(t):[]}}}function br(e){var t=e.key,r=e.limit,n=void 0===r?5:r,o=hr(t),i=o.getItem().slice(0,n);return{add:function(e){var t=e,r=(t._highlightResult,t._snippetResult,yr(t,dr)),a=i.findIndex((function(e){return e.objectID===r.objectID}));a>-1&&i.splice(a,1),i.unshift(r),i=i.slice(0,n),o.setItem(i)},remove:function(e){i=i.filter((function(t){return t.objectID!==e.objectID})),o.setItem(i)},getAll:function(){return i}}}function gr(e){const t=`algoliasearch-client-js-${e.key}`;let r;const n=()=>(void 0===r&&(r=e.localStorage||window.localStorage),r),o=()=>JSON.parse(n().getItem(t)||"{}"),i=e=>{n().setItem(t,JSON.stringify(e))};return{get:(t,r,n={miss:()=>Promise.resolve()})=>Promise.resolve().then((()=>{(()=>{const t=e.timeToLive?1e3*e.timeToLive:null,r=o(),n=Object.fromEntries(Object.entries(r).filter((([,e])=>void 0!==e.timestamp)));if(i(n),!t)return;const a=Object.fromEntries(Object.entries(n).filter((([,e])=>{const r=(new Date).getTime();return!(e.timestamp+tPromise.all([e?e.value:r(),void 0!==e]))).then((([e,t])=>Promise.all([e,t||n.miss(e)]))).then((([e])=>e)),set:(e,r)=>Promise.resolve().then((()=>{const i=o();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:r},n().setItem(t,JSON.stringify(i)),r})),delete:e=>Promise.resolve().then((()=>{const r=o();delete r[JSON.stringify(e)],n().setItem(t,JSON.stringify(r))})),clear:()=>Promise.resolve().then((()=>{n().removeItem(t)}))}}function Or(e){const t=[...e.caches],r=t.shift();return void 0===r?{get:(e,t,r={miss:()=>Promise.resolve()})=>t().then((e=>Promise.all([e,r.miss(e)]))).then((([e])=>e)),set:(e,t)=>Promise.resolve(t),delete:e=>Promise.resolve(),clear:()=>Promise.resolve()}:{get:(e,n,o={miss:()=>Promise.resolve()})=>r.get(e,n,o).catch((()=>Or({caches:t}).get(e,n,o))),set:(e,n)=>r.set(e,n).catch((()=>Or({caches:t}).set(e,n))),delete:e=>r.delete(e).catch((()=>Or({caches:t}).delete(e))),clear:()=>r.clear().catch((()=>Or({caches:t}).clear()))}}function Sr(e={serializable:!0}){let t={};return{get(r,n,o={miss:()=>Promise.resolve()}){const i=JSON.stringify(r);if(i in t)return Promise.resolve(e.serializable?JSON.parse(t[i]):t[i]);const a=n(),c=o&&o.miss||(()=>Promise.resolve());return a.then((e=>c(e))).then((()=>a))},set:(r,n)=>(t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)),delete:e=>(delete t[JSON.stringify(e)],Promise.resolve()),clear:()=>(t={},Promise.resolve())}}function jr(e){let t=e.length-1;for(;t>0;t--){const r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function wr(e,t){return t?(Object.keys(t).forEach((r=>{e[r]=t[r](e)})),e):e}function Er(e,...t){let r=0;return e.replace(/%s/g,(()=>encodeURIComponent(t[r++])))}const Pr="4.20.0",Ir={WithinQueryParameters:0,WithinHeaders:1};function Dr(e,t){const r=e||{},n=r.data||{};return Object.keys(r).forEach((e=>{-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}const Ar={Read:1,Write:2,Any:3},kr={Up:1,Down:2,Timeouted:3},xr=12e4;function Cr(e,t=kr.Up){return{...e,status:t,lastUpdate:Date.now()}}function _r(e){return"string"==typeof e?{protocol:"https",url:e,accept:Ar.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||Ar.Any}}const Nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};function Tr(e,t){return Promise.all(t.map((t=>e.get(t,(()=>Promise.resolve(Cr(t))))))).then((e=>{const r=e.filter((e=>function(e){return e.status===kr.Up||Date.now()-e.lastUpdate>xr}(e))),n=e.filter((e=>function(e){return e.status===kr.Timeouted&&Date.now()-e.lastUpdate<=xr}(e))),o=[...r,...n];return{getTimeout:(e,t)=>(0===n.length&&0===e?1:n.length+3+e)*t,statelessHosts:o.length>0?o.map((e=>_r(e))):t}}))}const qr=(e,t)=>(e=>{const t=e.status;return e.isTimedOut||(({isTimedOut:e,status:t})=>!e&&0==~~t)(e)||2!=~~(t/100)&&4!=~~(t/100)})(e)?t.onRetry(e):(({status:e})=>2==~~(e/100))(e)?t.onSuccess(e):t.onFail(e);function Rr(e,t,r,n){const o=[],i=function(e,t){if(e.method===Nr.Get||void 0===e.data&&void 0===t.data)return;const r=Array.isArray(e.data)?e.data:{...e.data,...t.data};return JSON.stringify(r)}(r,n),a=function(e,t){const r={...e.headers,...t.headers},n={};return Object.keys(r).forEach((e=>{const t=r[e];n[e.toLowerCase()]=t})),n}(e,n),c=r.method,l=r.method!==Nr.Get?{}:{...r.data,...n.data},u={"x-algolia-agent":e.userAgent.value,...e.queryParameters,...l,...n.queryParameters};let s=0;const f=(t,l)=>{const m=t.pop();if(void 0===m)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:Fr(o)};const p={data:i,headers:a,method:c,url:Mr(m,r.path,u),connectTimeout:l(s,e.timeouts.connect),responseTimeout:l(s,n.timeout)},v=e=>{const r={request:p,response:e,host:m,triesLeft:t.length};return o.push(r),r},d={onSuccess:e=>function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e),onRetry(r){const n=v(r);return r.isTimedOut&&s++,Promise.all([e.logger.info("Retryable failure",Ur(n)),e.hostsCache.set(m,Cr(m,r.isTimedOut?kr.Timeouted:kr.Down))]).then((()=>f(t,l)))},onFail(e){throw v(e),function({content:e,status:t},r){let n=e;try{n=JSON.parse(e).message}catch(o){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(n,t,r)}(e,Fr(o))}};return e.requester.send(p).then((e=>qr(e,d)))};return Tr(e.hostsCache,t).then((e=>f([...e.statelessHosts].reverse(),e.getTimeout)))}function Lr(e){const t={value:`Algolia for JavaScript (${e})`,add(e){const r=`; ${e.segment}${void 0!==e.version?` (${e.version})`:""}`;return-1===t.value.indexOf(r)&&(t.value=`${t.value}${r}`),t}};return t}function Mr(e,t,r){const n=Hr(r);let o=`${e.protocol}://${e.url}/${"/"===t.charAt(0)?t.substr(1):t}`;return n.length&&(o+=`?${n}`),o}function Hr(e){return Object.keys(e).map((t=>{return Er("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function Fr(e){return e.map((e=>Ur(e)))}function Ur(e){const t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...e,request:{...e.request,headers:{...e.request.headers,...t}}}}const Br=e=>{const t=e.appId,r=function(e,t,r){const n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:()=>e===Ir.WithinHeaders?n:{},queryParameters:()=>e===Ir.WithinQueryParameters?n:{}}}(void 0!==e.authMode?e.authMode:Ir.WithinHeaders,t,e.apiKey),n=function(e){const{hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,hosts:l,queryParameters:u,headers:s}=e,f={hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,headers:s,queryParameters:u,hosts:l.map((e=>_r(e))),read(e,t){const r=Dr(t,f.timeouts.read),n=()=>Rr(f,f.hosts.filter((e=>0!=(e.accept&Ar.Read))),e,r);if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();const o={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(o,(()=>f.requestsCache.get(o,(()=>f.requestsCache.set(o,n()).then((e=>Promise.all([f.requestsCache.delete(o),e])),(e=>Promise.all([f.requestsCache.delete(o),Promise.reject(e)]))).then((([e,t])=>t))))),{miss:e=>f.responsesCache.set(o,e)})},write:(e,t)=>Rr(f,f.hosts.filter((e=>0!=(e.accept&Ar.Write))),e,Dr(t,f.timeouts.write))};return f}({hosts:[{url:`${t}-dsn.algolia.net`,accept:Ar.Read},{url:`${t}.algolia.net`,accept:Ar.Write}].concat(jr([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}])),...e,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...e.headers},queryParameters:{...r.queryParameters(),...e.queryParameters}}),o={transporter:n,appId:t,addAlgoliaAgent(e,t){n.userAgent.add({segment:e,version:t})},clearCache:()=>Promise.all([n.requestsCache.clear(),n.responsesCache.clear()]).then((()=>{}))};return wr(o,e.methods)},Vr=e=>(t,r)=>t.method===Nr.Get?e.transporter.read(t,r):e.transporter.write(t,r),Kr=e=>(t,r={})=>wr({transporter:e.transporter,appId:e.appId,indexName:t},r.methods),$r=e=>(t,r)=>{const n=t.map((e=>({...e,params:Hr(e.params||{})})));return e.transporter.read({method:Nr.Post,path:"1/indexes/*/queries",data:{requests:n},cacheable:!0},r)},Jr=e=>(t,r)=>Promise.all(t.map((t=>{const{facetName:n,facetQuery:o,...i}=t.params;return Kr(e)(t.indexName,{methods:{searchForFacetValues:Qr}}).searchForFacetValues(n,o,{...r,...i})}))),zr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n),Wr=e=>(t,r)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),Qr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n),Zr={Debug:1,Info:2,Error:3};function Gr(e,t,r){const n={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:e=>new Promise((t=>{const r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((t=>r.setRequestHeader(t,e.headers[t])));const n=(e,n)=>setTimeout((()=>{r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e),o=n(e.connectTimeout,"Connection timeout");let i;r.onreadystatechange=()=>{r.readyState>r.OPENED&&void 0===i&&(clearTimeout(o),i=n(e.responseTimeout,"Socket timeout"))},r.onerror=()=>{0===r.status&&(clearTimeout(o),clearTimeout(i),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=()=>{clearTimeout(o),clearTimeout(i),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))},logger:(o=Zr.Error,{debug:(e,t)=>(Zr.Debug>=o&&console.debug(e,t),Promise.resolve()),info:(e,t)=>(Zr.Info>=o&&console.info(e,t),Promise.resolve()),error:(e,t)=>(console.error(e,t),Promise.resolve())}),responsesCache:Sr(),requestsCache:Sr({serializable:!1}),hostsCache:Or({caches:[gr({key:`${Pr}-${e}`}),Sr()]}),userAgent:Lr(Pr).add({segment:"Browser",version:"lite"}),authMode:Ir.WithinQueryParameters};var o;return Br({...n,...r,methods:{search:$r,searchForFacetValues:Jr,multipleQueries:$r,multipleSearchForFacetValues:Jr,customRequest:Vr,initIndex:e=>t=>Kr(e)(t,{methods:{search:Wr,searchForFacetValues:Qr,findAnswers:zr}})}})}Gr.version=Pr;const Xr=Gr;var Yr="3.5.2";function en(){}function tn(e){return e}function rn(e){return 1===e.button||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey}function nn(e,t,r){return e.reduce((function(e,n){var o=t(n);return e.hasOwnProperty(o)||(e[o]=[]),e[o].length<(r||5)&&e[o].push(n),e}),{})}var on=["footer","searchBox"];function an(){return an=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function pn(e){var t=e.appId,r=e.apiKey,n=e.indexName,o=e.placeholder,i=void 0===o?"Search docs":o,a=e.searchParameters,c=e.maxResultsPerGroup,l=e.onClose,u=void 0===l?en:l,s=e.transformItems,f=void 0===s?tn:s,m=e.hitComponent,p=void 0===m?St:m,v=e.resultsFooterComponent,d=void 0===v?function(){return null}:v,y=e.navigator,h=e.initialScrollY,b=void 0===h?0:h,g=e.transformSearchClient,O=void 0===g?tn:g,S=e.disableUserPersonalization,j=void 0!==S&&S,w=e.initialQuery,E=void 0===w?"":w,P=e.translations,I=void 0===P?{}:P,D=e.getMissingResultsUrl,A=e.insights,k=void 0!==A&&A,x=I.footer,C=I.searchBox,_=mn(I,on),N=sn(yt.useState({query:"",collections:[],completion:null,context:{},isOpen:!1,activeItemId:null,status:"idle"}),2),T=N[0],q=N[1],R=yt.useRef(null),L=yt.useRef(null),M=yt.useRef(null),H=yt.useRef(null),F=yt.useRef(null),U=yt.useRef(10),B=yt.useRef("undefined"!=typeof window?window.getSelection().toString().slice(0,ht):"").current,V=yt.useRef(E||B).current,K=function(e,t,r){return yt.useMemo((function(){var n=Xr(e,t);return n.addAlgoliaAgent("docsearch",Yr),!1===/docsearch.js \(.*\)/.test(n.transporter.userAgent.value)&&n.addAlgoliaAgent("docsearch-react",Yr),r(n)}),[e,t,r])}(t,r,O),$=yt.useRef(br({key:"__DOCSEARCH_FAVORITE_SEARCHES__".concat(n),limit:10})).current,J=yt.useRef(br({key:"__DOCSEARCH_RECENT_SEARCHES__".concat(n),limit:0===$.getAll().length?7:4})).current,z=yt.useCallback((function(e){if(!j){var t="content"===e.type?e.__docsearch_parent:e;t&&-1===$.getAll().findIndex((function(e){return e.objectID===t.objectID}))&&J.add(t)}}),[$,J,j]),W=yt.useCallback((function(e){if(T.context.algoliaInsightsPlugin&&e.__autocomplete_id){var t=e,r={eventName:"Item Selected",index:t.__autocomplete_indexName,items:[t],positions:[e.__autocomplete_id],queryID:t.__autocomplete_queryID};T.context.algoliaInsightsPlugin.insights.clickedObjectIDsAfterSearch(r)}}),[T.context.algoliaInsightsPlugin]),Q=yt.useMemo((function(){return dt({id:"docsearch",defaultActiveItemId:0,placeholder:i,openOnFocus:!0,initialState:{query:V,context:{searchSuggestions:[]}},insights:k,navigator:y,onStateChange:function(e){q(e.state)},getSources:function(e){var o=e.query,i=e.state,l=e.setContext,s=e.setStatus;if(!o)return j?[]:[{sourceId:"recentSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return J.getAll()}},{sourceId:"favoriteSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return $.getAll()}}];var m=Boolean(k);return K.search([{query:o,indexName:n,params:ln({attributesToRetrieve:["hierarchy.lvl0","hierarchy.lvl1","hierarchy.lvl2","hierarchy.lvl3","hierarchy.lvl4","hierarchy.lvl5","hierarchy.lvl6","content","type","url"],attributesToSnippet:["hierarchy.lvl1:".concat(U.current),"hierarchy.lvl2:".concat(U.current),"hierarchy.lvl3:".concat(U.current),"hierarchy.lvl4:".concat(U.current),"hierarchy.lvl5:".concat(U.current),"hierarchy.lvl6:".concat(U.current),"content:".concat(U.current)],snippetEllipsisText:"\u2026",highlightPreTag:"",highlightPostTag:"",hitsPerPage:20,clickAnalytics:m},a)}]).catch((function(e){throw"RetryError"===e.name&&s("error"),e})).then((function(e){var o=e.results[0],a=o.hits,s=o.nbHits,p=nn(a,(function(e){return Qt(e)}),c);i.context.searchSuggestions.length0&&(X(),F.current&&F.current.focus())}),[V,X]),yt.useEffect((function(){function e(){if(L.current){var e=.01*window.innerHeight;L.current.style.setProperty("--docsearch-vh","".concat(e,"px"))}}return e(),window.addEventListener("resize",e),function(){window.removeEventListener("resize",e)}}),[]),yt.createElement("div",an({ref:R},G({"aria-expanded":!0}),{className:["DocSearch","DocSearch-Container","stalled"===T.status&&"DocSearch-Container--Stalled","error"===T.status&&"DocSearch-Container--Errored"].filter(Boolean).join(" "),role:"button",tabIndex:0,onMouseDown:function(e){e.target===e.currentTarget&&u()}}),yt.createElement("div",{className:"DocSearch-Modal",ref:L},yt.createElement("header",{className:"DocSearch-SearchBar",ref:M},yt.createElement(vr,an({},Q,{state:T,autoFocus:0===V.length,inputRef:F,isFromSelection:Boolean(V)&&V===B,translations:C,onClose:u}))),yt.createElement("div",{className:"DocSearch-Dropdown",ref:H},yt.createElement(lr,an({},Q,{indexName:n,state:T,hitComponent:p,resultsFooterComponent:d,disableUserPersonalization:j,recentSearches:J,favoriteSearches:$,inputRef:F,translations:_,getMissingResultsUrl:D,onItemClick:function(e,t){W(e),z(e),rn(t)||u()}}))),yt.createElement("footer",{className:"DocSearch-Footer"},yt.createElement(Ot,{translations:x}))))}}}]); \ No newline at end of file diff --git a/es/assets/js/14d2cd64.5c92038e.js b/es/assets/js/14d2cd64.5c92038e.js new file mode 100644 index 000000000000..50405439f7bd --- /dev/null +++ b/es/assets/js/14d2cd64.5c92038e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2901],{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 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 s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="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,o=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,h=u["".concat(i,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(h,s(s({ref:t},p),{},{components:n})):a.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:r,s[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={},s="State Management",l={unversionedId:"creator/development/state_management",id:"creator/development/state_management",title:"State Management",description:"All of Ethereal Engine's state management uses hookstate and react. Together, these tools give reactive, declarative, and controlled state management across any scope.",source:"@site/docs/2_creator/4_development/1_state_management.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/state_management",permalink:"/etherealengine-docs/es/docs/creator/development/state_management",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/1_state_management.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Projects",permalink:"/etherealengine-docs/es/docs/creator/development/projects_overview"},next:{title:"Entities, Components and Systems",permalink:"/etherealengine-docs/es/docs/creator/development/ecs"}},i={},c=[{value:"Scoped State",id:"scoped-state",level:2},{value:"Global State",id:"global-state",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"state-management"},"State Management"),(0,r.kt)("p",null,"All of Ethereal Engine's state management uses ",(0,r.kt)("a",{parentName:"p",href:"https://hookstate.js.org/"},"hookstate")," and ",(0,r.kt)("a",{parentName:"p",href:"https://react.dev/"},"react"),". Together, these tools give reactive, declarative, and controlled state management across any scope."),(0,r.kt)("h2",{id:"scoped-state"},"Scoped State"),(0,r.kt)("p",null,"Scoped state can be defined using the ",(0,r.kt)("inlineCode",{parentName:"p"},"useHookstate")," hook - this is vanilla hookstate, and is useful for state that is only used in a single component, or state that is only used in a single component tree."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-tsx"},"import { useHookstate } from '@hookstate/core'\n\nconst MyComponent = () => {\n const state = useHookstate({\n count: 0\n })\n return (\n
\n

Count: {state.count}

\n \n
\n )\n}\n")),(0,r.kt)("h2",{id:"global-state"},"Global State"),(0,r.kt)("p",null,"Global state definitions are wrapped in a 'store' which allows for automatic creation and cleanup as needed. This API as well as the underlying hookstate API can be imported from ",(0,r.kt)("inlineCode",{parentName:"p"},"@etherealengine/hyperflux"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="MyState.ts"',title:'"MyState.ts"'},"import { defineState } from '@etherealengine/hyperflux'\n\nconst MyState = defineState({\n name: 'MyState',\n initial: {\n count: 0\n }\n})\n")),(0,r.kt)("p",null,"Global state will be registered to the engine instance once it has been called with ",(0,r.kt)("inlineCode",{parentName:"p"},"getState")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"getMutableState"),". This will cause the state to be created if it does not exist, and will be cleaned up when the engine instance is destroyed."),(0,r.kt)("p",null,"It's proxy can be accessed with ",(0,r.kt)("inlineCode",{parentName:"p"},"Engine.instance.store.stateMap.MyState")," where ",(0,r.kt)("inlineCode",{parentName:"p"},"MyState")," is the name of the state."),(0,r.kt)("p",null,"When accessing the state, ",(0,r.kt)("inlineCode",{parentName:"p"},"getState")," returns the underlying object typed as readonly. This is useful for reading state values, but should not be used to write to state."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"import { getState } from '@etherealengine/hyperflux'\nimport { MyState } from './MyState'\n\nconst state = getState(MyState)\nconsole.log(state.count) // 0\nstate.count = 1 // Error: Cannot assign to 'count' because it is a read-only property.\n")),(0,r.kt)("p",null,"State can be mutated via the ",(0,r.kt)("inlineCode",{parentName:"p"},"getMutableState")," function, which returns a proxy to the state, which can be used to read and write state values. The proxy is reactive, so any changes to the state will cause the component to re-render."),(0,r.kt)("p",null,"The proxy returned can be wrapped in hookstate's reactive hook ",(0,r.kt)("inlineCode",{parentName:"p"},"useHookstate"),". This will cause the component to re-render when any state values are changed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-tsx"},"import { getMutableState, useHookstate } from '@etherealengine/hyperflux'\nimport { MyState } from './MyState'\n\nconst MyComponent = () => {\n const state = useHookstate(getMutableState(MyState))\n return (\n
\n

Count: {state.count}

\n \n
\n )\n}\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/15dae980.eb3148f9.js b/es/assets/js/15dae980.eb3148f9.js new file mode 100644 index 000000000000..f9a16db31a84 --- /dev/null +++ b/es/assets/js/15dae980.eb3148f9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1489],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>h});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},p=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),d=u(t),m=i,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||l;return t?a.createElement(h,o(o({ref:n},p),{},{components:t})):a.createElement(h,o({ref:n},p))}));function h(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var l=t.length,o=new Array(l);o[0]=m;var r={};for(var s in n)hasOwnProperty.call(n,s)&&(r[s]=n[s]);r.originalType=e,r[d]="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={},o="Installing on Windows with WSL2",r={unversionedId:"host/installation/windows_wsl",id:"host/installation/windows_wsl",title:"Installing on Windows with WSL2",description:"This guide is currently tested on Windows 10 (22H2) and Windows 11.",source:"@site/docs/1_host/1_installation/3_windows_wsl.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/windows_wsl",permalink:"/etherealengine-docs/es/docs/host/installation/windows_wsl",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/3_windows_wsl.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing on Windows 10+",permalink:"/etherealengine-docs/es/docs/host/installation/windows"},next:{title:"Advanced Setup",permalink:"/etherealengine-docs/es/docs/host/installation/advanced_setup"}},s={},u=[{value:"Install Windows Subsystem for Linux (WSL).",id:"install-windows-subsystem-for-linux-wsl",level:2},{value:"Install Docker Desktop",id:"install-docker-desktop",level:2},{value:"Install Node.",id:"install-node",level:2},{value:"Install Python 3",id:"install-python-3",level:2},{value:"Install Make",id:"install-make",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Initialize MariaDB server",id:"initialize-mariadb-server",level:2},{value:"Start Engine Stack",id:"start-engine-stack",level:2},{value:"Accept Certificates",id:"accept-certificates",level:2}],p={toc:u},d="wrapper";function c(e){let{components:n,...l}=e;return(0,i.kt)(d,(0,a.Z)({},p,l,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"installing-on-windows-with-wsl2"},"Installing on Windows with WSL2"),(0,i.kt)("p",null,"This guide is currently tested on Windows 10 (22H2) and Windows 11."),(0,i.kt)("h2",{id:"install-windows-subsystem-for-linux-wsl"},"Install Windows Subsystem for Linux (WSL)."),(0,i.kt)("p",null,"Remember to run Powershell in Administrator mode either by right clicking and selecting 'Run as administrator' or by typing PowerShell in 'Run' dialog box of Windows and pressing ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+Shift+Enter")," key combination."),(0,i.kt)("p",null,"Install Ubuntu distribution of Linux by executing the command:\n",(0,i.kt)("inlineCode",{parentName:"p"},"wsl --install --distribution Ubuntu"),"\nor\nInstall Ubuntu distribution of Linux from Microsoft Store by using guide ",(0,i.kt)("a",{parentName:"p",href:"https://learn.microsoft.com/en-us/windows/wsl/install"},"here"),"."),(0,i.kt)("p",null,"Alternatively, you can follow these instructions as well:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://pureinfotech.com/install-wsl-windows-11/"},"How to install WSL")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/install-manual"},"Manual installation steps for WSL"))),(0,i.kt)("p",null,"Once WSL is installed, make sure to:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#set-up-your-linux-username-and-password"},"Set up your Linux username and password")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#update-and-upgrade-packages"},"Update and upgrade packages")),(0,i.kt)("li",{parentName:"ul"},"Verify Ubuntu distribution using the command: 'lsb_release -a'"),(0,i.kt)("li",{parentName:"ul"},"You can verify WSL and Ubuntu installation by using the command in PowerShell: 'wsl -l -v'")),(0,i.kt)("h2",{id:"install-docker-desktop"},"Install Docker Desktop"),(0,i.kt)("p",null,"Install docker desktop with WSL 2 backend. You can find the instructions ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/windows-install/"},"here"),"."),(0,i.kt)("p",null,"Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting ",(0,i.kt)("inlineCode",{parentName:"p"},"Settings > Resources > WSL Integration"),". Enable integration with Ubuntu. Make sure to hit 'Apply & Restart'."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Docker Desktop WSL Distro",src:t(5238).Z,width:"1918",height:"1033"})),(0,i.kt)("h2",{id:"install-node"},"Install Node."),(0,i.kt)("p",null,"Run Powershell in Administrator mode. Run Ubuntu using command : ",(0,i.kt)("inlineCode",{parentName:"p"},"wsl"),". After logging on run the following command: ",(0,i.kt)("inlineCode",{parentName:"p"},"cd ~/")," to ensure that the installation of Node and other packages mentioned below is done in Ubuntu."),(0,i.kt)("p",null,"In your WSL Ubuntu terminal, if node (",(0,i.kt)("inlineCode",{parentName:"p"},"node --version"),") isn't already installed on your machine. You can do so by first installing ",(0,i.kt)("inlineCode",{parentName:"p"},"nvm")," by running following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash\nsource ~/.profile\n\nexport NVM_DIR="$HOME/.nvm"\n[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh" # This loads nvm\n[ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n')),(0,i.kt)("p",null,"You can verify nvm by using ",(0,i.kt)("inlineCode",{parentName:"p"},"nvm --version")," command. Afterwards, install Node (version between 16.0 and 18.0 both inclusive) by using:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"nvm install --lts\n")),(0,i.kt)("p",null,"You can verify node version by using ",(0,i.kt)("inlineCode",{parentName:"p"},"node --version")," command."),(0,i.kt)("h2",{id:"install-python-3"},"Install Python 3"),(0,i.kt)("p",null,"In your WSL Ubuntu terminal, if python 3 (",(0,i.kt)("inlineCode",{parentName:"p"},"pip3 --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y python3-pip\n")),(0,i.kt)("p",null,"You can verify python3 by using ",(0,i.kt)("inlineCode",{parentName:"p"},"python3 --version")," command."),(0,i.kt)("h2",{id:"install-make"},"Install Make"),(0,i.kt)("p",null,"In your WSL Ubuntu terminal, if make (",(0,i.kt)("inlineCode",{parentName:"p"},"make --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y build-essential\n")),(0,i.kt)("p",null,"You can verify make by using ",(0,i.kt)("inlineCode",{parentName:"p"},"make --version")," command."),(0,i.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,i.kt)("p",null,"Clone Ethereal Engine repo on your machine by running following command in WSL Ubuntu terminal. You can check the directory in which you are sitting by the command: ",(0,i.kt)("inlineCode",{parentName:"p"},"pwd")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/etherealengine/etherealengine --depth 1\n")),(0,i.kt)("p",null,"Change directory to the location where etherealengine repo is cloned ",(0,i.kt)("inlineCode",{parentName:"p"},"cd etherealengine"),"\nIf ",(0,i.kt)("inlineCode",{parentName:"p"},".env.local")," file does not exist in the root of your repo folder then create it by duplicating ",(0,i.kt)("inlineCode",{parentName:"p"},".env.local.default"),". Command: ",(0,i.kt)("inlineCode",{parentName:"p"},"cp .env.local.default .env.local")),(0,i.kt)("p",null,"Afterwards, install npm packages using:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm install\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Note: If you face issue related to ",(0,i.kt)("inlineCode",{parentName:"p"},"mediasoup")," while doing npm install. Then remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"mediasoup")," package from ",(0,i.kt)("inlineCode",{parentName:"p"},"packages/instanceserver/package.json")," file of Ethereal Engine source code. And run ",(0,i.kt)("inlineCode",{parentName:"p"},"npm install")," again. Afterwards, run:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm install mediasoup@3 -w @etherealengine/instanceserver\n")),(0,i.kt)("h2",{id:"initialize-mariadb-server"},"Initialize MariaDB server"),(0,i.kt)("p",null,"If you are running the engine for the first time then you will need to initialize the database with tables and data. You can do so by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev-reinit\n")),(0,i.kt)("h2",{id:"start-engine-stack"},"Start Engine Stack"),(0,i.kt)("p",null,"You can run Ethereal Engine stack by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev\n")),(0,i.kt)("p",null,"Now run Ethereal Engine in browser by navigating to ",(0,i.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default"},"this link"),". "),(0,i.kt)("h2",{id:"accept-certificates"},"Accept Certificates"),(0,i.kt)("p",null,"You'll have to tell your browser to ignore the insecure connections when you try to load the website."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates."),(0,i.kt)("li",{parentName:"ol"},"Open Developer tools in your browser by clicking the side menu with three dots, then ",(0,i.kt)("inlineCode",{parentName:"li"},"More tools > Developer tools")," (or use ",(0,i.kt)("inlineCode",{parentName:"li"},"Ctrl+Shift+I"),") and then go to the 'Console' tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.")))}c.isMDXComponent=!0},5238:(e,n,t)=>{t.d(n,{Z:()=>a});const a=t.p+"assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg"}}]); \ No newline at end of file diff --git a/es/assets/js/17896441.07f91ca7.js b/es/assets/js/17896441.07f91ca7.js new file mode 100644 index 000000000000..43ea566a7b0f --- /dev/null +++ b/es/assets/js/17896441.07f91ca7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7918],{903:(e,t,a)=>{a.r(t),a.d(t,{default:()=>pe});var n=a(7294),l=a(833),r=a(902);const o=n.createContext(null);function s(e){let{children:t,content:a}=e;const l=function(e){return(0,n.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(a);return n.createElement(o.Provider,{value:l},t)}function c(){const e=(0,n.useContext)(o);if(null===e)throw new r.i6("DocProvider");return e}function i(){const{metadata:e,frontMatter:t,assets:a}=c();return n.createElement(l.d,{title:e.title,description:e.description,keywords:t.keywords,image:a.image??t.image})}var d=a(6010),m=a(7524),u=a(7462),b=a(5999),p=a(9960);function E(e){const{permalink:t,title:a,subLabel:l,isNext:r}=e;return n.createElement(p.Z,{className:(0,d.Z)("pagination-nav__link",r?"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))}function h(e){const{previous:t,next:a}=e;return n.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,b.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&n.createElement(E,(0,u.Z)({},t,{subLabel:n.createElement(b.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),a&&n.createElement(E,(0,u.Z)({},a,{subLabel:n.createElement(b.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function v(){const{metadata:e}=c();return n.createElement(h,{previous:e.previous,next:e.next})}var g=a(2263),f=a(143),_=a(5281),N=a(373),Z=a(4477);const k={unreleased:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(b.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(b.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 C(e){const t=k[e.versionMetadata.banner];return n.createElement(t,e)}function L(e){let{versionLabel:t,to:a,onClick:l}=e;return n.createElement(b.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(p.Z,{to:a,onClick:l},n.createElement(b.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 T(e){let{className:t,versionMetadata:a}=e;const{siteConfig:{title:l}}=(0,g.Z)(),{pluginId:r}=(0,f.gA)({failfast:!0}),{savePreferredVersionName:o}=(0,N.J)(r),{latestDocSuggestion:s,latestVersionSuggestion:c}=(0,f.Jo)(r),i=s??(m=c).docs.find((e=>e.id===m.mainDocId));var m;return n.createElement("div",{className:(0,d.Z)(t,_.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},n.createElement("div",null,n.createElement(C,{siteTitle:l,versionMetadata:a})),n.createElement("div",{className:"margin-top--md"},n.createElement(L,{versionLabel:c.label,to:i.path,onClick:()=>o(c.name)})))}function U(e){let{className:t}=e;const a=(0,Z.E)();return a.banner?n.createElement(T,{className:t,versionMetadata:a}):null}function w(e){let{className:t}=e;const a=(0,Z.E)();return a.badge?n.createElement("span",{className:(0,d.Z)(t,_.k.docs.docVersionBadge,"badge badge--secondary")},n.createElement(b.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:a.label}},"Version: {versionLabel}")):null}function x(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:a}=e;return n.createElement(b.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:n.createElement("b",null,n.createElement("time",{dateTime:new Date(1e3*t).toISOString()},a))}}," on {date}")}function y(e){let{lastUpdatedBy:t}=e;return n.createElement(b.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:n.createElement("b",null,t)}}," by {user}")}function A(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:a,lastUpdatedBy:l}=e;return n.createElement("span",{className:_.k.common.lastUpdated},n.createElement(b.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&a?n.createElement(x,{lastUpdatedAt:t,formattedLastUpdatedAt:a}):"",byUser:l?n.createElement(y,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}const M={iconEdit:"iconEdit_Z9Sw"};function B(e){let{className:t,...a}=e;return n.createElement("svg",(0,u.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,d.Z)(M.iconEdit,t),"aria-hidden":"true"},a),n.createElement("g",null,n.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function I(e){let{editUrl:t}=e;return n.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:_.k.common.editThisPage},n.createElement(B,null),n.createElement(b.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const V={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function H(e){let{permalink:t,label:a,count:l}=e;return n.createElement(p.Z,{href:t,className:(0,d.Z)(V.tag,l?V.tagWithCount:V.tagRegular)},a,l&&n.createElement("span",null,l))}const P={tags:"tags_jXut",tag:"tag_QGVx"};function D(e){let{tags:t}=e;return n.createElement(n.Fragment,null,n.createElement("b",null,n.createElement(b.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),n.createElement("ul",{className:(0,d.Z)(P.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:a}=e;return n.createElement("li",{key:a,className:P.tag},n.createElement(H,{label:t,permalink:a}))}))))}const S={lastUpdated:"lastUpdated_vwxv"};function F(e){return n.createElement("div",{className:(0,d.Z)(_.k.docs.docFooterTagsRow,"row margin-bottom--sm")},n.createElement("div",{className:"col"},n.createElement(D,e)))}function R(e){let{editUrl:t,lastUpdatedAt:a,lastUpdatedBy:l,formattedLastUpdatedAt:r}=e;return n.createElement("div",{className:(0,d.Z)(_.k.docs.docFooterEditMetaRow,"row")},n.createElement("div",{className:"col"},t&&n.createElement(I,{editUrl:t})),n.createElement("div",{className:(0,d.Z)("col",S.lastUpdated)},(a||l)&&n.createElement(A,{lastUpdatedAt:a,formattedLastUpdatedAt:r,lastUpdatedBy:l})))}function z(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:a,formattedLastUpdatedAt:l,lastUpdatedBy:r,tags:o}=e,s=o.length>0,i=!!(t||a||r);return s||i?n.createElement("footer",{className:(0,d.Z)(_.k.docs.docFooter,"docusaurus-mt-lg")},s&&n.createElement(F,{tags:o}),i&&n.createElement(R,{editUrl:t,lastUpdatedAt:a,lastUpdatedBy:r,formattedLastUpdatedAt:l})):null}var O=a(6043),j=a(3743);const q={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function G(e){let{collapsed:t,...a}=e;return n.createElement("button",(0,u.Z)({type:"button"},a,{className:(0,d.Z)("clean-btn",q.tocCollapsibleButton,!t&&q.tocCollapsibleButtonExpanded,a.className)}),n.createElement(b.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const W={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function J(e){let{toc:t,className:a,minHeadingLevel:l,maxHeadingLevel:r}=e;const{collapsed:o,toggleCollapsed:s}=(0,O.u)({initialState:!0});return n.createElement("div",{className:(0,d.Z)(W.tocCollapsible,!o&&W.tocCollapsibleExpanded,a)},n.createElement(G,{collapsed:o,onClick:s}),n.createElement(O.z,{lazy:!0,className:W.tocCollapsibleContent,collapsed:o},n.createElement(j.Z,{toc:t,minHeadingLevel:l,maxHeadingLevel:r})))}const Q={tocMobile:"tocMobile_ITEo"};function X(){const{toc:e,frontMatter:t}=c();return n.createElement(J,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.Z)(_.k.docs.docTocMobile,Q.tocMobile)})}var Y=a(9407);function $(){const{toc:e,frontMatter:t}=c();return n.createElement(Y.Z,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:_.k.docs.docTocDesktop})}var K=a(2503),ee=a(7432);function te(e){let{children:t}=e;const a=function(){const{metadata:e,frontMatter:t,contentTitle:a}=c();return t.hide_title||void 0!==a?null:e.title}();return n.createElement("div",{className:(0,d.Z)(_.k.docs.docMarkdown,"markdown")},a&&n.createElement("header",null,n.createElement(K.Z,{as:"h1"},a)),n.createElement(ee.Z,null,t))}var ae=a(2802),ne=a(8596),le=a(4996);function re(e){return n.createElement("svg",(0,u.Z)({viewBox:"0 0 24 24"},e),n.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 oe={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function se(){const e=(0,le.Z)("/");return n.createElement("li",{className:"breadcrumbs__item"},n.createElement(p.Z,{"aria-label":(0,b.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},n.createElement(re,{className:oe.breadcrumbHomeIcon})))}const ce={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function ie(e){let{children:t,href:a,isLast:l}=e;const r="breadcrumbs__link";return l?n.createElement("span",{className:r,itemProp:"name"},t):a?n.createElement(p.Z,{className:r,href:a,itemProp:"item"},n.createElement("span",{itemProp:"name"},t)):n.createElement("span",{className:r},t)}function de(e){let{children:t,active:a,index:l,addMicrodata:r}=e;return n.createElement("li",(0,u.Z)({},r&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.Z)("breadcrumbs__item",{"breadcrumbs__item--active":a})}),t,n.createElement("meta",{itemProp:"position",content:String(l+1)}))}function me(){const e=(0,ae.s1)(),t=(0,ne.Ns)();return e?n.createElement("nav",{className:(0,d.Z)(_.k.docs.docBreadcrumbs,ce.breadcrumbsContainer),"aria-label":(0,b.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},n.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&n.createElement(se,null),e.map(((t,a)=>{const l=a===e.length-1;return n.createElement(de,{key:a,active:l,index:a,addMicrodata:!!t.href},n.createElement(ie,{href:t.href,isLast:l},t.label))})))):null}const ue={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function be(e){let{children:t}=e;const a=function(){const{frontMatter:e,toc:t}=c(),a=(0,m.i)(),l=e.hide_table_of_contents,r=!l&&t.length>0;return{hidden:l,mobile:r?n.createElement(X,null):void 0,desktop:!r||"desktop"!==a&&"ssr"!==a?void 0:n.createElement($,null)}}();return n.createElement("div",{className:"row"},n.createElement("div",{className:(0,d.Z)("col",!a.hidden&&ue.docItemCol)},n.createElement(U,null),n.createElement("div",{className:ue.docItemContainer},n.createElement("article",null,n.createElement(me,null),n.createElement(w,null),a.mobile,n.createElement(te,null,t),n.createElement(z,null)),n.createElement(v,null))),a.desktop&&n.createElement("div",{className:"col col--3"},a.desktop))}function pe(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,a=e.content;return n.createElement(s,{content:e.content},n.createElement(l.FG,{className:t},n.createElement(i,null),n.createElement(be,null,n.createElement(a,null))))}},4477:(e,t,a)=>{a.d(t,{E:()=>s,q:()=>o});var n=a(7294),l=a(902);const r=n.createContext(null);function o(e){let{children:t,version:a}=e;return n.createElement(r.Provider,{value:a},t)}function s(){const e=(0,n.useContext)(r);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/es/assets/js/1a4e3797.dd8146f2.js b/es/assets/js/1a4e3797.dd8146f2.js new file mode 100644 index 000000000000..7cb9dd049db4 --- /dev/null +++ b/es/assets/js/1a4e3797.dd8146f2.js @@ -0,0 +1,2 @@ +/*! For license information please see 1a4e3797.dd8146f2.js.LICENSE.txt */ +(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7920],{7331:e=>{function t(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=t,t.prototype._events=void 0,t.prototype._maxListeners=void 0,t.defaultMaxListeners=10,t.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},t.prototype.emit=function(e){var t,a,s,c,u,o;if(this._events||(this._events={}),"error"===e&&(!this._events.error||n(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i(a=this._events[e]))return!1;if(r(a))switch(arguments.length){case 1:a.call(this);break;case 2:a.call(this,arguments[1]);break;case 3:a.call(this,arguments[1],arguments[2]);break;default:c=Array.prototype.slice.call(arguments,1),a.apply(this,c)}else if(n(a))for(c=Array.prototype.slice.call(arguments,1),s=(o=a.slice()).length,u=0;u0&&this._events[e].length>s&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}return i.listener=t,this.on(e,i),this},t.prototype.removeListener=function(e,t){var i,a,s,c;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(s=(i=this._events[e]).length,a=-1,i===t||r(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(n(i)){for(c=s;c-- >0;)if(i[c]===t||i[c].listener&&i[c].listener===t){a=c;break}if(a<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(a,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},t.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},t.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},t.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},t.listenerCount=function(e,t){return e.listenerCount(t)}},8131:(e,t,r)=>{"use strict";var n=r(9374),i=r(7775),a=r(3076);function s(e,t,r){return new n(e,t,r)}s.version=r(4336),s.AlgoliaSearchHelper=n,s.SearchParameters=i,s.SearchResults=a,e.exports=s},8078:(e,t,r)=>{"use strict";var n=r(7331);function i(e,t){this.main=e,this.fn=t,this.lastResults=null}r(4853)(i,n),i.prototype.detach=function(){this.removeAllListeners(),this.main.detachDerivedHelper(this)},i.prototype.getModifiedState=function(e){return this.fn(e)},e.exports=i},2437:(e,t,r)=>{"use strict";var n=r(2344),i=r(116),a=r(9803),s={addRefinement:function(e,t,r){if(s.isRefined(e,t,r))return e;var i=""+r,a=e[t]?e[t].concat(i):[i],c={};return c[t]=a,n({},c,e)},removeRefinement:function(e,t,r){if(void 0===r)return s.clearRefinement(e,(function(e,r){return t===r}));var n=""+r;return s.clearRefinement(e,(function(e,r){return t===r&&n===e}))},toggleRefinement:function(e,t,r){if(void 0===r)throw new Error("toggleRefinement should be used with a value");return s.isRefined(e,t,r)?s.removeRefinement(e,t,r):s.addRefinement(e,t,r)},clearRefinement:function(e,t,r){if(void 0===t)return i(e)?{}:e;if("string"==typeof t)return a(e,[t]);if("function"==typeof t){var n=!1,s=Object.keys(e).reduce((function(i,a){var s=e[a]||[],c=s.filter((function(e){return!t(e,a,r)}));return c.length!==s.length&&(n=!0),i[a]=c,i}),{});return n?s:e}},isRefined:function(e,t,r){var n=Boolean(e[t])&&e[t].length>0;if(void 0===r||!n)return n;var i=""+r;return-1!==e[t].indexOf(i)}};e.exports=s},7775:(e,t,r)=>{"use strict";var n=r(2344),i=r(7888),a=r(2686),s=r(185),c=r(116),u=r(9803),o=r(8023),h=r(6801),f=r(2437);function l(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((function(e,r){return l(t[r],e)})):e===t}function m(e){var t=e?m._parseNumbers(e):{};void 0===t.userToken||h(t.userToken)||console.warn("[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}"),this.facets=t.facets||[],this.disjunctiveFacets=t.disjunctiveFacets||[],this.hierarchicalFacets=t.hierarchicalFacets||[],this.facetsRefinements=t.facetsRefinements||{},this.facetsExcludes=t.facetsExcludes||{},this.disjunctiveFacetsRefinements=t.disjunctiveFacetsRefinements||{},this.numericRefinements=t.numericRefinements||{},this.tagRefinements=t.tagRefinements||[],this.hierarchicalFacetsRefinements=t.hierarchicalFacetsRefinements||{};var r=this;Object.keys(t).forEach((function(e){var n=-1!==m.PARAMETERS.indexOf(e),i=void 0!==t[e];!n&&i&&(r[e]=t[e])}))}m.PARAMETERS=Object.keys(new m),m._parseNumbers=function(e){if(e instanceof m)return e;var t={};if(["aroundPrecision","aroundRadius","getRankingInfo","minWordSizefor2Typos","minWordSizefor1Typo","page","maxValuesPerFacet","distinct","minimumAroundRadius","hitsPerPage","minProximity"].forEach((function(r){var n=e[r];if("string"==typeof n){var i=parseFloat(n);t[r]=isNaN(i)?n:i}})),Array.isArray(e.insideBoundingBox)&&(t.insideBoundingBox=e.insideBoundingBox.map((function(e){return Array.isArray(e)?e.map((function(e){return parseFloat(e)})):e}))),e.numericRefinements){var r={};Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t]||{};r[t]={},Object.keys(n).forEach((function(e){var i=n[e].map((function(e){return Array.isArray(e)?e.map((function(e){return"string"==typeof e?parseFloat(e):e})):"string"==typeof e?parseFloat(e):e}));r[t][e]=i}))})),t.numericRefinements=r}return s({},e,t)},m.make=function(e){var t=new m(e);return(e.hierarchicalFacets||[]).forEach((function(e){if(e.rootPath){var r=t.getHierarchicalRefinement(e.name);r.length>0&&0!==r[0].indexOf(e.rootPath)&&(t=t.clearRefinements(e.name)),0===(r=t.getHierarchicalRefinement(e.name)).length&&(t=t.toggleHierarchicalFacetRefinement(e.name,e.rootPath))}})),t},m.validate=function(e,t){var r=t||{};return e.tagFilters&&r.tagRefinements&&r.tagRefinements.length>0?new Error("[Tags] Cannot switch from the managed tag API to the advanced API. It is probably an error, if it is really what you want, you should first clear the tags with clearTags method."):e.tagRefinements.length>0&&r.tagFilters?new Error("[Tags] Cannot switch from the advanced tag API to the managed API. It is probably an error, if it is not, you should first clear the tags with clearTags method."):e.numericFilters&&r.numericRefinements&&c(r.numericRefinements)?new Error("[Numeric filters] Can't switch from the advanced to the managed API. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):c(e.numericRefinements)&&r.numericFilters?new Error("[Numeric filters] Can't switch from the managed API to the advanced. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):null},m.prototype={constructor:m,clearRefinements:function(e){var t={numericRefinements:this._clearNumericRefinements(e),facetsRefinements:f.clearRefinement(this.facetsRefinements,e,"conjunctiveFacet"),facetsExcludes:f.clearRefinement(this.facetsExcludes,e,"exclude"),disjunctiveFacetsRefinements:f.clearRefinement(this.disjunctiveFacetsRefinements,e,"disjunctiveFacet"),hierarchicalFacetsRefinements:f.clearRefinement(this.hierarchicalFacetsRefinements,e,"hierarchicalFacet")};return t.numericRefinements===this.numericRefinements&&t.facetsRefinements===this.facetsRefinements&&t.facetsExcludes===this.facetsExcludes&&t.disjunctiveFacetsRefinements===this.disjunctiveFacetsRefinements&&t.hierarchicalFacetsRefinements===this.hierarchicalFacetsRefinements?this:this.setQueryParameters(t)},clearTags:function(){return void 0===this.tagFilters&&0===this.tagRefinements.length?this:this.setQueryParameters({tagFilters:void 0,tagRefinements:[]})},setIndex:function(e){return e===this.index?this:this.setQueryParameters({index:e})},setQuery:function(e){return e===this.query?this:this.setQueryParameters({query:e})},setPage:function(e){return e===this.page?this:this.setQueryParameters({page:e})},setFacets:function(e){return this.setQueryParameters({facets:e})},setDisjunctiveFacets:function(e){return this.setQueryParameters({disjunctiveFacets:e})},setHitsPerPage:function(e){return this.hitsPerPage===e?this:this.setQueryParameters({hitsPerPage:e})},setTypoTolerance:function(e){return this.typoTolerance===e?this:this.setQueryParameters({typoTolerance:e})},addNumericRefinement:function(e,t,r){var n=o(r);if(this.isNumericRefined(e,t,n))return this;var i=s({},this.numericRefinements);return i[e]=s({},i[e]),i[e][t]?(i[e][t]=i[e][t].slice(),i[e][t].push(n)):i[e][t]=[n],this.setQueryParameters({numericRefinements:i})},getConjunctiveRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsRefinements[e]||[]},getDisjunctiveRefinements:function(e){return this.isDisjunctiveFacet(e)&&this.disjunctiveFacetsRefinements[e]||[]},getHierarchicalRefinement:function(e){return this.hierarchicalFacetsRefinements[e]||[]},getExcludeRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsExcludes[e]||[]},removeNumericRefinement:function(e,t,r){var n=r;return void 0!==n?this.isNumericRefined(e,t,n)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,i){return i===e&&r.op===t&&l(r.val,o(n))}))}):this:void 0!==t?this.isNumericRefined(e,t)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,n){return n===e&&r.op===t}))}):this:this.isNumericRefined(e)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(t,r){return r===e}))}):this},getNumericRefinements:function(e){return this.numericRefinements[e]||{}},getNumericRefinement:function(e,t){return this.numericRefinements[e]&&this.numericRefinements[e][t]},_clearNumericRefinements:function(e){if(void 0===e)return c(this.numericRefinements)?{}:this.numericRefinements;if("string"==typeof e)return u(this.numericRefinements,[e]);if("function"==typeof e){var t=!1,r=this.numericRefinements,n=Object.keys(r).reduce((function(n,i){var a=r[i],s={};return a=a||{},Object.keys(a).forEach((function(r){var n=a[r]||[],c=[];n.forEach((function(t){e({val:t,op:r},i,"numeric")||c.push(t)})),c.length!==n.length&&(t=!0),s[r]=c})),n[i]=s,n}),{});return t?n:this.numericRefinements}},addFacet:function(e){return this.isConjunctiveFacet(e)?this:this.setQueryParameters({facets:this.facets.concat([e])})},addDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this:this.setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.concat([e])})},addHierarchicalFacet:function(e){if(this.isHierarchicalFacet(e.name))throw new Error("Cannot declare two hierarchical facets with the same name: `"+e.name+"`");return this.setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.concat([e])})},addFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this:this.setQueryParameters({facetsRefinements:f.addRefinement(this.facetsRefinements,e,t)})},addExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this:this.setQueryParameters({facetsExcludes:f.addRefinement(this.facetsExcludes,e,t)})},addDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this:this.setQueryParameters({disjunctiveFacetsRefinements:f.addRefinement(this.disjunctiveFacetsRefinements,e,t)})},addTagRefinement:function(e){if(this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.concat(e)};return this.setQueryParameters(t)},removeFacet:function(e){return this.isConjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({facets:this.facets.filter((function(t){return t!==e}))}):this},removeDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.filter((function(t){return t!==e}))}):this},removeHierarchicalFacet:function(e){return this.isHierarchicalFacet(e)?this.clearRefinements(e).setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.filter((function(t){return t.name!==e}))}):this},removeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this.setQueryParameters({facetsRefinements:f.removeRefinement(this.facetsRefinements,e,t)}):this},removeExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this.setQueryParameters({facetsExcludes:f.removeRefinement(this.facetsExcludes,e,t)}):this},removeDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this.setQueryParameters({disjunctiveFacetsRefinements:f.removeRefinement(this.disjunctiveFacetsRefinements,e,t)}):this},removeTagRefinement:function(e){if(!this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.filter((function(t){return t!==e}))};return this.setQueryParameters(t)},toggleRefinement:function(e,t){return this.toggleFacetRefinement(e,t)},toggleFacetRefinement:function(e,t){if(this.isHierarchicalFacet(e))return this.toggleHierarchicalFacetRefinement(e,t);if(this.isConjunctiveFacet(e))return this.toggleConjunctiveFacetRefinement(e,t);if(this.isDisjunctiveFacet(e))return this.toggleDisjunctiveFacetRefinement(e,t);throw new Error("Cannot refine the undeclared facet "+e+"; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets")},toggleConjunctiveFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsRefinements:f.toggleRefinement(this.facetsRefinements,e,t)})},toggleExcludeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsExcludes:f.toggleRefinement(this.facetsExcludes,e,t)})},toggleDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return this.setQueryParameters({disjunctiveFacetsRefinements:f.toggleRefinement(this.disjunctiveFacetsRefinements,e,t)})},toggleHierarchicalFacetRefinement:function(e,t){if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration");var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e)),i={};return void 0!==this.hierarchicalFacetsRefinements[e]&&this.hierarchicalFacetsRefinements[e].length>0&&(this.hierarchicalFacetsRefinements[e][0]===t||0===this.hierarchicalFacetsRefinements[e][0].indexOf(t+r))?-1===t.indexOf(r)?i[e]=[]:i[e]=[t.slice(0,t.lastIndexOf(r))]:i[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},i,this.hierarchicalFacetsRefinements)})},addHierarchicalFacetRefinement:function(e,t){if(this.isHierarchicalFacetRefined(e))throw new Error(e+" is already refined.");if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration.");var r={};return r[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},r,this.hierarchicalFacetsRefinements)})},removeHierarchicalFacetRefinement:function(e){if(!this.isHierarchicalFacetRefined(e))return this;var t={};return t[e]=[],this.setQueryParameters({hierarchicalFacetsRefinements:n({},t,this.hierarchicalFacetsRefinements)})},toggleTagRefinement:function(e){return this.isTagRefined(e)?this.removeTagRefinement(e):this.addTagRefinement(e)},isDisjunctiveFacet:function(e){return this.disjunctiveFacets.indexOf(e)>-1},isHierarchicalFacet:function(e){return void 0!==this.getHierarchicalFacetByName(e)},isConjunctiveFacet:function(e){return this.facets.indexOf(e)>-1},isFacetRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsRefinements,e,t)},isExcludeRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsExcludes,e,t)},isDisjunctiveFacetRefined:function(e,t){return!!this.isDisjunctiveFacet(e)&&f.isRefined(this.disjunctiveFacetsRefinements,e,t)},isHierarchicalFacetRefined:function(e,t){if(!this.isHierarchicalFacet(e))return!1;var r=this.getHierarchicalRefinement(e);return t?-1!==r.indexOf(t):r.length>0},isNumericRefined:function(e,t,r){if(void 0===r&&void 0===t)return Boolean(this.numericRefinements[e]);var n=this.numericRefinements[e]&&void 0!==this.numericRefinements[e][t];if(void 0===r||!n)return n;var a,s,c=o(r),u=void 0!==(a=this.numericRefinements[e][t],s=c,i(a,(function(e){return l(e,s)})));return n&&u},isTagRefined:function(e){return-1!==this.tagRefinements.indexOf(e)},getRefinedDisjunctiveFacets:function(){var e=this,t=a(Object.keys(this.numericRefinements).filter((function(t){return Object.keys(e.numericRefinements[t]).length>0})),this.disjunctiveFacets);return Object.keys(this.disjunctiveFacetsRefinements).filter((function(t){return e.disjunctiveFacetsRefinements[t].length>0})).concat(t).concat(this.getRefinedHierarchicalFacets()).sort()},getRefinedHierarchicalFacets:function(){var e=this;return a(this.hierarchicalFacets.map((function(e){return e.name})),Object.keys(this.hierarchicalFacetsRefinements).filter((function(t){return e.hierarchicalFacetsRefinements[t].length>0}))).sort()},getUnrefinedDisjunctiveFacets:function(){var e=this.getRefinedDisjunctiveFacets();return this.disjunctiveFacets.filter((function(t){return-1===e.indexOf(t)}))},managedParameters:["index","facets","disjunctiveFacets","facetsRefinements","hierarchicalFacets","facetsExcludes","disjunctiveFacetsRefinements","numericRefinements","tagRefinements","hierarchicalFacetsRefinements"],getQueryParams:function(){var e=this.managedParameters,t={},r=this;return Object.keys(this).forEach((function(n){var i=r[n];-1===e.indexOf(n)&&void 0!==i&&(t[n]=i)})),t},setQueryParameter:function(e,t){if(this[e]===t)return this;var r={};return r[e]=t,this.setQueryParameters(r)},setQueryParameters:function(e){if(!e)return this;var t=m.validate(this,e);if(t)throw t;var r=this,n=m._parseNumbers(e),i=Object.keys(this).reduce((function(e,t){return e[t]=r[t],e}),{}),a=Object.keys(n).reduce((function(e,t){var r=void 0!==e[t],i=void 0!==n[t];return r&&!i?u(e,[t]):(i&&(e[t]=n[t]),e)}),i);return new this.constructor(a)},resetPage:function(){return void 0===this.page?this:this.setPage(0)},_getHierarchicalFacetSortBy:function(e){return e.sortBy||["isRefined:desc","name:asc"]},_getHierarchicalFacetSeparator:function(e){return e.separator||" > "},_getHierarchicalRootPath:function(e){return e.rootPath||null},_getHierarchicalShowParentLevel:function(e){return"boolean"!=typeof e.showParentLevel||e.showParentLevel},getHierarchicalFacetByName:function(e){return i(this.hierarchicalFacets,(function(t){return t.name===e}))},getHierarchicalFacetBreadcrumb:function(e){if(!this.isHierarchicalFacet(e))return[];var t=this.getHierarchicalRefinement(e)[0];if(!t)return[];var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e));return t.split(r).map((function(e){return e.trim()}))},toString:function(){return JSON.stringify(this,null,2)}},e.exports=m},210:(e,t,r)=>{"use strict";e.exports=function(e){return function(t,r){var n=e.hierarchicalFacets[r],o=e.hierarchicalFacetsRefinements[n.name]&&e.hierarchicalFacetsRefinements[n.name][0]||"",h=e._getHierarchicalFacetSeparator(n),f=e._getHierarchicalRootPath(n),l=e._getHierarchicalShowParentLevel(n),m=a(e._getHierarchicalFacetSortBy(n)),d=t.every((function(e){return e.exhaustive})),p=function(e,t,r,n,a){return function(o,h,f){var l=o;if(f>0){var m=0;for(l=o;m{"use strict";var n=r(4587),i=r(2344),a=r(4039),s=r(7888),c=r(9725),u=r(2293),o=r(185),h=r(2148),f=a.escapeFacetValue,l=a.unescapeFacetValue,m=r(210);function d(e){var t={};return e.forEach((function(e,r){t[e]=r})),t}function p(e,t,r){t&&t[r]&&(e.stats=t[r])}function v(e,t,r){var a=t[0];this._rawResults=t;var u=this;Object.keys(a).forEach((function(e){u[e]=a[e]})),Object.keys(r||{}).forEach((function(e){u[e]=r[e]})),this.processingTimeMS=t.reduce((function(e,t){return void 0===t.processingTimeMS?e:e+t.processingTimeMS}),0),this.disjunctiveFacets=[],this.hierarchicalFacets=e.hierarchicalFacets.map((function(){return[]})),this.facets=[];var h=e.getRefinedDisjunctiveFacets(),f=d(e.facets),v=d(e.disjunctiveFacets),g=1,y=a.facets||{};Object.keys(y).forEach((function(t){var r,n,i=y[t],o=(r=e.hierarchicalFacets,n=t,s(r,(function(e){return(e.attributes||[]).indexOf(n)>-1})));if(o){var h=o.attributes.indexOf(t),l=c(e.hierarchicalFacets,(function(e){return e.name===o.name}));u.hierarchicalFacets[l][h]={attribute:t,data:i,exhaustive:a.exhaustiveFacetsCount}}else{var m,d=-1!==e.disjunctiveFacets.indexOf(t),g=-1!==e.facets.indexOf(t);d&&(m=v[t],u.disjunctiveFacets[m]={name:t,data:i,exhaustive:a.exhaustiveFacetsCount},p(u.disjunctiveFacets[m],a.facets_stats,t)),g&&(m=f[t],u.facets[m]={name:t,data:i,exhaustive:a.exhaustiveFacetsCount},p(u.facets[m],a.facets_stats,t))}})),this.hierarchicalFacets=n(this.hierarchicalFacets),h.forEach((function(r){var n=t[g],s=n&&n.facets?n.facets:{},h=e.getHierarchicalFacetByName(r);Object.keys(s).forEach((function(t){var r,f=s[t];if(h){r=c(e.hierarchicalFacets,(function(e){return e.name===h.name}));var m=c(u.hierarchicalFacets[r],(function(e){return e.attribute===t}));if(-1===m)return;u.hierarchicalFacets[r][m].data=o({},u.hierarchicalFacets[r][m].data,f)}else{r=v[t];var d=a.facets&&a.facets[t]||{};u.disjunctiveFacets[r]={name:t,data:i({},f,d),exhaustive:n.exhaustiveFacetsCount},p(u.disjunctiveFacets[r],n.facets_stats,t),e.disjunctiveFacetsRefinements[t]&&e.disjunctiveFacetsRefinements[t].forEach((function(n){!u.disjunctiveFacets[r].data[n]&&e.disjunctiveFacetsRefinements[t].indexOf(l(n))>-1&&(u.disjunctiveFacets[r].data[n]=0)}))}})),g++})),e.getRefinedHierarchicalFacets().forEach((function(r){var n=e.getHierarchicalFacetByName(r),a=e._getHierarchicalFacetSeparator(n),s=e.getHierarchicalRefinement(r);0===s.length||s[0].split(a).length<2||t.slice(g).forEach((function(t){var r=t&&t.facets?t.facets:{};Object.keys(r).forEach((function(t){var o=r[t],h=c(e.hierarchicalFacets,(function(e){return e.name===n.name})),f=c(u.hierarchicalFacets[h],(function(e){return e.attribute===t}));if(-1!==f){var l={};if(s.length>0){var m=s[0].split(a)[0];l[m]=u.hierarchicalFacets[h][f].data[m]}u.hierarchicalFacets[h][f].data=i(l,o,u.hierarchicalFacets[h][f].data)}})),g++}))})),Object.keys(e.facetsExcludes).forEach((function(t){var r=e.facetsExcludes[t],n=f[t];u.facets[n]={name:t,data:y[t],exhaustive:a.exhaustiveFacetsCount},r.forEach((function(e){u.facets[n]=u.facets[n]||{name:t},u.facets[n].data=u.facets[n].data||{},u.facets[n].data[e]=0}))})),this.hierarchicalFacets=this.hierarchicalFacets.map(m(e)),this.facets=n(this.facets),this.disjunctiveFacets=n(this.disjunctiveFacets),this._state=e}function g(e,t){function r(e){return e.name===t}if(e._state.isConjunctiveFacet(t)){var n=s(e.facets,r);return n?Object.keys(n.data).map((function(r){var i=f(r);return{name:r,escapedValue:i,count:n.data[r],isRefined:e._state.isFacetRefined(t,i),isExcluded:e._state.isExcludeRefined(t,r)}})):[]}if(e._state.isDisjunctiveFacet(t)){var i=s(e.disjunctiveFacets,r);return i?Object.keys(i.data).map((function(r){var n=f(r);return{name:r,escapedValue:n,count:i.data[r],isRefined:e._state.isDisjunctiveFacetRefined(t,n)}})):[]}if(e._state.isHierarchicalFacet(t)){var a=s(e.hierarchicalFacets,r);if(!a)return a;var c=e._state.getHierarchicalFacetByName(t),u=e._state._getHierarchicalFacetSeparator(c),o=l(e._state.getHierarchicalRefinement(t)[0]||"");0===o.indexOf(c.rootPath)&&(o=o.replace(c.rootPath+u,""));var h=o.split(u);return h.unshift(t),y(a,h,0),a}}function y(e,t,r){e.isRefined=e.name===t[r],e.data&&e.data.forEach((function(e){y(e,t,r+1)}))}function R(e,t,r,n){if(n=n||0,Array.isArray(t))return e(t,r[n]);if(!t.data||0===t.data.length)return t;var a=t.data.map((function(t){return R(e,t,r,n+1)})),s=e(a,r[n]);return i({data:s},t)}function F(e,t){var r=s(e,(function(e){return e.name===t}));return r&&r.stats}function b(e,t,r,n,i){var a=s(i,(function(e){return e.name===r})),c=a&&a.data&&a.data[n]?a.data[n]:0,u=a&&a.exhaustive||!1;return{type:t,attributeName:r,name:n,count:c,exhaustive:u}}v.prototype.getFacetByName=function(e){function t(t){return t.name===e}return s(this.facets,t)||s(this.disjunctiveFacets,t)||s(this.hierarchicalFacets,t)},v.DEFAULT_SORT=["isRefined:desc","count:desc","name:asc"],v.prototype.getFacetValues=function(e,t){var r=g(this,e);if(r){var n,a=i({},t,{sortBy:v.DEFAULT_SORT,facetOrdering:!(t&&t.sortBy)}),s=this;if(Array.isArray(r))n=[e];else n=s._state.getHierarchicalFacetByName(r.name).attributes;return R((function(e,t){if(a.facetOrdering){var r=function(e,t){return e.renderingContent&&e.renderingContent.facetOrdering&&e.renderingContent.facetOrdering.values&&e.renderingContent.facetOrdering.values[t]}(s,t);if(r)return function(e,t){var r=[],n=[],i=(t.order||[]).reduce((function(e,t,r){return e[t]=r,e}),{});e.forEach((function(e){var t=e.path||e.name;void 0!==i[t]?r[i[t]]=e:n.push(e)})),r=r.filter((function(e){return e}));var a,s=t.sortRemainingBy;return"hidden"===s?r:(a="alpha"===s?[["path","name"],["asc","asc"]]:[["count"],["desc"]],r.concat(h(n,a[0],a[1])))}(e,r)}if(Array.isArray(a.sortBy)){var n=u(a.sortBy,v.DEFAULT_SORT);return h(e,n[0],n[1])}if("function"==typeof a.sortBy)return function(e,t){return t.sort(e)}(a.sortBy,e);throw new Error("options.sortBy is optional but if defined it must be either an array of string (predicates) or a sorting function")}),r,n)}},v.prototype.getFacetStats=function(e){return this._state.isConjunctiveFacet(e)?F(this.facets,e):this._state.isDisjunctiveFacet(e)?F(this.disjunctiveFacets,e):void 0},v.prototype.getRefinements=function(){var e=this._state,t=this,r=[];return Object.keys(e.facetsRefinements).forEach((function(n){e.facetsRefinements[n].forEach((function(i){r.push(b(e,"facet",n,i,t.facets))}))})),Object.keys(e.facetsExcludes).forEach((function(n){e.facetsExcludes[n].forEach((function(i){r.push(b(e,"exclude",n,i,t.facets))}))})),Object.keys(e.disjunctiveFacetsRefinements).forEach((function(n){e.disjunctiveFacetsRefinements[n].forEach((function(i){r.push(b(e,"disjunctive",n,i,t.disjunctiveFacets))}))})),Object.keys(e.hierarchicalFacetsRefinements).forEach((function(n){e.hierarchicalFacetsRefinements[n].forEach((function(i){r.push(function(e,t,r,n){var i=e.getHierarchicalFacetByName(t),a=e._getHierarchicalFacetSeparator(i),c=r.split(a),u=s(n,(function(e){return e.name===t})),o=c.reduce((function(e,t){var r=e&&s(e.data,(function(e){return e.name===t}));return void 0!==r?r:e}),u),h=o&&o.count||0,f=o&&o.exhaustive||!1,l=o&&o.path||"";return{type:"hierarchical",attributeName:t,name:l,count:h,exhaustive:f}}(e,n,i,t.hierarchicalFacets))}))})),Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t];Object.keys(n).forEach((function(e){n[e].forEach((function(n){r.push({type:"numeric",attributeName:t,name:n,numericValue:n,operator:e})}))}))})),e.tagRefinements.forEach((function(e){r.push({type:"tag",attributeName:"_tags",name:e})})),r},e.exports=v},9374:(e,t,r)=>{"use strict";var n=r(7331),i=r(8078),a=r(4039).escapeFacetValue,s=r(4853),c=r(185),u=r(116),o=r(9803),h=r(6394),f=r(7775),l=r(3076),m=r(4336);function d(e,t,r){"function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+m+")"),this.setClient(e);var n=r||{};n.index=t,this.state=f.make(n),this.lastResults=null,this._queryId=0,this._lastQueryIdReceived=-1,this.derivedHelpers=[],this._currentNbQueries=0}function p(e){if(e<0)throw new Error("Page requested below 0.");return this._change({state:this.state.setPage(e),isPageReset:!1}),this}function v(){return this.state.page}s(d,n),d.prototype.search=function(){return this._search({onlyWithDerivedHelpers:!1}),this},d.prototype.searchOnlyWithDerivedHelpers=function(){return this._search({onlyWithDerivedHelpers:!0}),this},d.prototype.getQuery=function(){var e=this.state;return h._getHitsSearchParams(e)},d.prototype.searchOnce=function(e,t){var r=e?this.state.setQueryParameters(e):this.state,n=h._getQueries(r.index,r),i=this;if(this._currentNbQueries++,this.emit("searchOnce",{state:r}),!t)return this.client.search(n).then((function(e){return i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),{content:new l(r,e.results),state:r,_originalResponse:e}}),(function(e){throw i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),e}));this.client.search(n).then((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(null,new l(r,e.results),r)})).catch((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(e,null,r)}))},d.prototype.findAnswers=function(e){console.warn("[algoliasearch-helper] answers is no longer supported");var t=this.state,r=this.derivedHelpers[0];if(!r)return Promise.resolve([]);var n=r.getModifiedState(t),i=c({attributesForPrediction:e.attributesForPrediction,nbHits:e.nbHits},{params:o(h._getHitsSearchParams(n),["attributesToSnippet","hitsPerPage","restrictSearchableAttributes","snippetEllipsisText"])}),a="search for answers was called, but this client does not have a function client.initIndex(index).findAnswers";if("function"!=typeof this.client.initIndex)throw new Error(a);var s=this.client.initIndex(n.index);if("function"!=typeof s.findAnswers)throw new Error(a);return s.findAnswers(n.query,e.queryLanguages,i)},d.prototype.searchForFacetValues=function(e,t,r,n){var i="function"==typeof this.client.searchForFacetValues,s="function"==typeof this.client.initIndex;if(!i&&!s&&"function"!=typeof this.client.search)throw new Error("search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues");var c=this.state.setQueryParameters(n||{}),u=c.isDisjunctiveFacet(e),o=h.getSearchForFacetQuery(e,t,r,c);this._currentNbQueries++;var f,l=this;return i?f=this.client.searchForFacetValues([{indexName:c.index,params:o}]):s?f=this.client.initIndex(c.index).searchForFacetValues(o):(delete o.facetName,f=this.client.search([{type:"facet",facet:e,indexName:c.index,params:o}]).then((function(e){return e.results[0]}))),this.emit("searchForFacetValues",{state:c,facet:e,query:t}),f.then((function(t){return l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),(t=Array.isArray(t)?t[0]:t).facetHits.forEach((function(t){t.escapedValue=a(t.value),t.isRefined=u?c.isDisjunctiveFacetRefined(e,t.escapedValue):c.isFacetRefined(e,t.escapedValue)})),t}),(function(e){throw l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),e}))},d.prototype.setQuery=function(e){return this._change({state:this.state.resetPage().setQuery(e),isPageReset:!0}),this},d.prototype.clearRefinements=function(e){return this._change({state:this.state.resetPage().clearRefinements(e),isPageReset:!0}),this},d.prototype.clearTags=function(){return this._change({state:this.state.resetPage().clearTags(),isPageReset:!0}),this},d.prototype.addDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addDisjunctiveRefine=function(){return this.addDisjunctiveFacetRefinement.apply(this,arguments)},d.prototype.addHierarchicalFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addHierarchicalFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().addNumericRefinement(e,t,r),isPageReset:!0}),this},d.prototype.addFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addRefine=function(){return this.addFacetRefinement.apply(this,arguments)},d.prototype.addFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().addExcludeRefinement(e,t),isPageReset:!0}),this},d.prototype.addExclude=function(){return this.addFacetExclusion.apply(this,arguments)},d.prototype.addTag=function(e){return this._change({state:this.state.resetPage().addTagRefinement(e),isPageReset:!0}),this},d.prototype.removeNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().removeNumericRefinement(e,t,r),isPageReset:!0}),this},d.prototype.removeDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.removeDisjunctiveRefine=function(){return this.removeDisjunctiveFacetRefinement.apply(this,arguments)},d.prototype.removeHierarchicalFacetRefinement=function(e){return this._change({state:this.state.resetPage().removeHierarchicalFacetRefinement(e),isPageReset:!0}),this},d.prototype.removeFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.removeRefine=function(){return this.removeFacetRefinement.apply(this,arguments)},d.prototype.removeFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().removeExcludeRefinement(e,t),isPageReset:!0}),this},d.prototype.removeExclude=function(){return this.removeFacetExclusion.apply(this,arguments)},d.prototype.removeTag=function(e){return this._change({state:this.state.resetPage().removeTagRefinement(e),isPageReset:!0}),this},d.prototype.toggleFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().toggleExcludeFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.toggleExclude=function(){return this.toggleFacetExclusion.apply(this,arguments)},d.prototype.toggleRefinement=function(e,t){return this.toggleFacetRefinement(e,t)},d.prototype.toggleFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().toggleFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.toggleRefine=function(){return this.toggleFacetRefinement.apply(this,arguments)},d.prototype.toggleTag=function(e){return this._change({state:this.state.resetPage().toggleTagRefinement(e),isPageReset:!0}),this},d.prototype.nextPage=function(){var e=this.state.page||0;return this.setPage(e+1)},d.prototype.previousPage=function(){var e=this.state.page||0;return this.setPage(e-1)},d.prototype.setCurrentPage=p,d.prototype.setPage=p,d.prototype.setIndex=function(e){return this._change({state:this.state.resetPage().setIndex(e),isPageReset:!0}),this},d.prototype.setQueryParameter=function(e,t){return this._change({state:this.state.resetPage().setQueryParameter(e,t),isPageReset:!0}),this},d.prototype.setState=function(e){return this._change({state:f.make(e),isPageReset:!1}),this},d.prototype.overrideStateWithoutTriggeringChangeEvent=function(e){return this.state=new f(e),this},d.prototype.hasRefinements=function(e){return!!u(this.state.getNumericRefinements(e))||(this.state.isConjunctiveFacet(e)?this.state.isFacetRefined(e):this.state.isDisjunctiveFacet(e)?this.state.isDisjunctiveFacetRefined(e):!!this.state.isHierarchicalFacet(e)&&this.state.isHierarchicalFacetRefined(e))},d.prototype.isExcluded=function(e,t){return this.state.isExcludeRefined(e,t)},d.prototype.isDisjunctiveRefined=function(e,t){return this.state.isDisjunctiveFacetRefined(e,t)},d.prototype.hasTag=function(e){return this.state.isTagRefined(e)},d.prototype.isTagRefined=function(){return this.hasTagRefinements.apply(this,arguments)},d.prototype.getIndex=function(){return this.state.index},d.prototype.getCurrentPage=v,d.prototype.getPage=v,d.prototype.getTags=function(){return this.state.tagRefinements},d.prototype.getRefinements=function(e){var t=[];if(this.state.isConjunctiveFacet(e))this.state.getConjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"conjunctive"})})),this.state.getExcludeRefinements(e).forEach((function(e){t.push({value:e,type:"exclude"})}));else if(this.state.isDisjunctiveFacet(e)){this.state.getDisjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"disjunctive"})}))}var r=this.state.getNumericRefinements(e);return Object.keys(r).forEach((function(e){var n=r[e];t.push({value:n,operator:e,type:"numeric"})})),t},d.prototype.getNumericRefinement=function(e,t){return this.state.getNumericRefinement(e,t)},d.prototype.getHierarchicalFacetBreadcrumb=function(e){return this.state.getHierarchicalFacetBreadcrumb(e)},d.prototype._search=function(e){var t=this.state,r=[],n=[];e.onlyWithDerivedHelpers||(n=h._getQueries(t.index,t),r.push({state:t,queriesCount:n.length,helper:this}),this.emit("search",{state:t,results:this.lastResults}));var i=this.derivedHelpers.map((function(e){var n=e.getModifiedState(t),i=n.index?h._getQueries(n.index,n):[];return r.push({state:n,queriesCount:i.length,helper:e}),e.emit("search",{state:n,results:e.lastResults}),i})),a=Array.prototype.concat.apply(n,i),s=this._queryId++;if(this._currentNbQueries++,!a.length)return Promise.resolve({results:[]}).then(this._dispatchAlgoliaResponse.bind(this,r,s));try{this.client.search(a).then(this._dispatchAlgoliaResponse.bind(this,r,s)).catch(this._dispatchAlgoliaError.bind(this,s))}catch(c){this.emit("error",{error:c})}},d.prototype._dispatchAlgoliaResponse=function(e,t,r){if(!(t0},d.prototype._change=function(e){var t=e.state,r=e.isPageReset;t!==this.state&&(this.state=t,this.emit("change",{state:this.state,results:this.lastResults,isPageReset:r}))},d.prototype.clearCache=function(){return this.client.clearCache&&this.client.clearCache(),this},d.prototype.setClient=function(e){return this.client===e||("function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+m+")"),this.client=e),this},d.prototype.getClient=function(){return this.client},d.prototype.derive=function(e){var t=new i(this,e);return this.derivedHelpers.push(t),t},d.prototype.detachDerivedHelper=function(e){var t=this.derivedHelpers.indexOf(e);if(-1===t)throw new Error("Derived helper already detached");this.derivedHelpers.splice(t,1)},d.prototype.hasPendingRequests=function(){return this._currentNbQueries>0},e.exports=d},4587:e=>{"use strict";e.exports=function(e){return Array.isArray(e)?e.filter(Boolean):[]}},2344:e=>{"use strict";e.exports=function(){return Array.prototype.slice.call(arguments).reduceRight((function(e,t){return Object.keys(Object(t)).forEach((function(r){void 0!==t[r]&&(void 0!==e[r]&&delete e[r],e[r]=t[r])})),e}),{})}},4039:e=>{"use strict";e.exports={escapeFacetValue:function(e){return"string"!=typeof e?e:String(e).replace(/^-/,"\\-")},unescapeFacetValue:function(e){return"string"!=typeof e?e:e.replace(/^\\-/,"-")}}},7888:e=>{"use strict";e.exports=function(e,t){if(Array.isArray(e))for(var r=0;r{"use strict";e.exports=function(e,t){if(!Array.isArray(e))return-1;for(var r=0;r{"use strict";var n=r(7888);e.exports=function(e,t){var r=(t||[]).map((function(e){return e.split(":")}));return e.reduce((function(e,t){var i=t.split(":"),a=n(r,(function(e){return e[0]===i[0]}));return i.length>1||!a?(e[0].push(i[0]),e[1].push(i[1]),e):(e[0].push(a[0]),e[1].push(a[1]),e)}),[[],[]])}},4853:e=>{"use strict";e.exports=function(e,t){e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}},2686:e=>{"use strict";e.exports=function(e,t){return e.filter((function(r,n){return t.indexOf(r)>-1&&e.indexOf(r)===n}))}},185:e=>{"use strict";function t(e){return"function"==typeof e||Array.isArray(e)||"[object Object]"===Object.prototype.toString.call(e)}function r(e,n){if(e===n)return e;for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)&&"__proto__"!==i&&"constructor"!==i){var a=n[i],s=e[i];void 0!==s&&void 0===a||(t(s)&&t(a)?e[i]=r(s,a):e[i]="object"==typeof(c=a)&&null!==c?r(Array.isArray(c)?[]:{},c):c)}var c;return e}e.exports=function(e){t(e)||(e={});for(var n=1,i=arguments.length;n{"use strict";e.exports=function(e){return e&&Object.keys(e).length>0}},9803:e=>{"use strict";e.exports=function(e,t){if(null===e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n=0||(i[r]=e[r]);return i}},2148:e=>{"use strict";function t(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=void 0!==t,a=null===t;if(!a&&e>t||n&&i||!r)return 1;if(!n&&e=n.length?a:"desc"===n[i]?-a:a}return e.index-r.index})),i.map((function(e){return e.value}))}},8023:e=>{"use strict";e.exports=function e(t){if("number"==typeof t)return t;if("string"==typeof t)return parseFloat(t);if(Array.isArray(t))return t.map(e);throw new Error("The value should be a number, a parsable string or an array of those.")}},6394:(e,t,r)=>{"use strict";var n=r(185);function i(e){return Object.keys(e).sort().reduce((function(t,r){return t[r]=e[r],t}),{})}var a={_getQueries:function(e,t){var r=[];return r.push({indexName:e,params:a._getHitsSearchParams(t)}),t.getRefinedDisjunctiveFacets().forEach((function(n){r.push({indexName:e,params:a._getDisjunctiveFacetSearchParams(t,n)})})),t.getRefinedHierarchicalFacets().forEach((function(n){var i=t.getHierarchicalFacetByName(n),s=t.getHierarchicalRefinement(n),c=t._getHierarchicalFacetSeparator(i);if(s.length>0&&s[0].split(c).length>1){var u=s[0].split(c).slice(0,-1).reduce((function(e,t,r){return e.concat({attribute:i.attributes[r],value:0===r?t:[e[e.length-1].value,t].join(c)})}),[]);u.forEach((function(n,s){var c=a._getDisjunctiveFacetSearchParams(t,n.attribute,0===s);function o(e){return i.attributes.some((function(t){return t===e.split(":")[0]}))}var h=(c.facetFilters||[]).reduce((function(e,t){if(Array.isArray(t)){var r=t.filter((function(e){return!o(e)}));r.length>0&&e.push(r)}return"string"!=typeof t||o(t)||e.push(t),e}),[]),f=u[s-1];c.facetFilters=s>0?h.concat(f.attribute+":"+f.value):h.length>0?h:void 0,r.push({indexName:e,params:c})}))}})),r},_getHitsSearchParams:function(e){var t=e.facets.concat(e.disjunctiveFacets).concat(a._getHitsHierarchicalFacetsAttributes(e)).sort(),r=a._getFacetFilters(e),s=a._getNumericFilters(e),c=a._getTagFilters(e),u={facets:t.indexOf("*")>-1?["*"]:t,tagFilters:c};return r.length>0&&(u.facetFilters=r),s.length>0&&(u.numericFilters=s),i(n({},e.getQueryParams(),u))},_getDisjunctiveFacetSearchParams:function(e,t,r){var s=a._getFacetFilters(e,t,r),c=a._getNumericFilters(e,t),u=a._getTagFilters(e),o={hitsPerPage:0,page:0,analytics:!1,clickAnalytics:!1};u.length>0&&(o.tagFilters=u);var h=e.getHierarchicalFacetByName(t);return o.facets=h?a._getDisjunctiveHierarchicalFacetAttribute(e,h,r):t,c.length>0&&(o.numericFilters=c),s.length>0&&(o.facetFilters=s),i(n({},e.getQueryParams(),o))},_getNumericFilters:function(e,t){if(e.numericFilters)return e.numericFilters;var r=[];return Object.keys(e.numericRefinements).forEach((function(n){var i=e.numericRefinements[n]||{};Object.keys(i).forEach((function(e){var a=i[e]||[];t!==n&&a.forEach((function(t){if(Array.isArray(t)){var i=t.map((function(t){return n+e+t}));r.push(i)}else r.push(n+e+t)}))}))})),r},_getTagFilters:function(e){return e.tagFilters?e.tagFilters:e.tagRefinements.join(",")},_getFacetFilters:function(e,t,r){var n=[],i=e.facetsRefinements||{};Object.keys(i).sort().forEach((function(e){(i[e]||[]).sort().forEach((function(t){n.push(e+":"+t)}))}));var a=e.facetsExcludes||{};Object.keys(a).sort().forEach((function(e){(a[e]||[]).sort().forEach((function(t){n.push(e+":-"+t)}))}));var s=e.disjunctiveFacetsRefinements||{};Object.keys(s).sort().forEach((function(e){var r=s[e]||[];if(e!==t&&r&&0!==r.length){var i=[];r.sort().forEach((function(t){i.push(e+":"+t)})),n.push(i)}}));var c=e.hierarchicalFacetsRefinements||{};return Object.keys(c).sort().forEach((function(i){var a=(c[i]||[])[0];if(void 0!==a){var s,u,o=e.getHierarchicalFacetByName(i),h=e._getHierarchicalFacetSeparator(o),f=e._getHierarchicalRootPath(o);if(t===i){if(-1===a.indexOf(h)||!f&&!0===r||f&&f.split(h).length===a.split(h).length)return;f?(u=f.split(h).length-1,a=f):(u=a.split(h).length-2,a=a.slice(0,a.lastIndexOf(h))),s=o.attributes[u]}else u=a.split(h).length-1,s=o.attributes[u];s&&n.push([s+":"+a])}})),n},_getHitsHierarchicalFacetsAttributes:function(e){return e.hierarchicalFacets.reduce((function(t,r){var n=e.getHierarchicalRefinement(r.name)[0];if(!n)return t.push(r.attributes[0]),t;var i=e._getHierarchicalFacetSeparator(r),a=n.split(i).length,s=r.attributes.slice(0,a+1);return t.concat(s)}),[])},_getDisjunctiveHierarchicalFacetAttribute:function(e,t,r){var n=e._getHierarchicalFacetSeparator(t);if(!0===r){var i=e._getHierarchicalRootPath(t),a=0;return i&&(a=i.split(n).length),[t.attributes[a]]}var s=(e.getHierarchicalRefinement(t.name)[0]||"").split(n).length-1;return t.attributes.slice(0,s+1)},getSearchForFacetQuery:function(e,t,r,s){var c=s.isDisjunctiveFacet(e)?s.clearRefinements(e):s,u={facetQuery:t,facetName:e};return"number"==typeof r&&(u.maxFacetHits=r),i(n({},a._getHitsSearchParams(c),u))}};e.exports=a},6801:e=>{"use strict";e.exports=function(e){return null!==e&&/^[a-zA-Z0-9_-]{1,64}$/.test(e)}},4336:e=>{"use strict";e.exports="3.15.0"},290:function(e){e.exports=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(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 r(r){for(var n=1;n=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],n=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(n=(s=c.next()).done)&&(r.push(s.value),!t||r.length!==t);n=!0);}catch(e){i=!0,a=e}finally{try{n||null==c.return||c.return()}finally{if(i)throw a}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){c();var t=JSON.stringify(e);return a()[t]})).then((function(e){return Promise.all([e?e.value:t(),void 0!==e])})).then((function(e){var t=i(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var i=a();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:t},n().setItem(r,JSON.stringify(i)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function c(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return t().then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,i).catch((function(){return c({caches:t}).get(e,n,i)}))},set:function(e,n){return r.set(e,n).catch((function(){return c({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return c({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return c({caches:t}).clear()}))}}}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var s=n(),c=i&&i.miss||function(){return Promise.resolve()};return s.then((function(e){return c(e)})).then((function(){return s}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function o(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function h(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},p=1,v=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function R(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var F="GET",b="POST";function P(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),i=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:i.length>0?i.map((function(e){return R(e)})):t}}))}function j(e,t,n,i){var s=[],c=function(e,t){if(e.method!==F&&(void 0!==e.data||void 0!==t.data)){var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}}(n,i),u=function(e,t){var n=r(r({},e.headers),t.headers),i={};return Object.keys(n).forEach((function(e){var t=n[e];i[e.toLowerCase()]=t})),i}(e,i),o=n.method,h=n.method!==F?{}:r(r({},n.data),i.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),h),i.queryParameters),l=0,m=function t(r,a){var h=r.pop();if(void 0===h)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:O(s)};var m={data:c,headers:u,method:o,url:E(h,n.path,f),connectTimeout:a(l,e.timeouts.connect),responseTimeout:a(l,i.timeout)},d=function(e){var t={request:m,response:e,host:h,triesLeft:r.length};return s.push(t),t},p={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var i=d(n);return n.isTimedOut&&l++,Promise.all([e.logger.info("Retryable failure",w(i)),e.hostsCache.set(h,y(h,n.isTimedOut?g:v))]).then((function(){return t(r,a)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,i=r;try{i=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(i,n,t)}(e,O(s))}};return e.requester.send(m).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,p)}))};return P(e.hostsCache,t).then((function(e){return m(a(e.statelessHosts).reverse(),e.getTimeout)}))}function _(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function E(e,t,r){var n=x(r),i="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(i+="?".concat(n)),i}function x(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function O(e){return e.map((function(e){return w(e)}))}function w(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var N=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===l.WithinHeaders?n:{}},queryParameters:function(){return e===l.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:l.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,s=e.responsesCache,c=e.timeouts,u=e.userAgent,o=e.hosts,h=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:s,timeouts:c,userAgent:u,headers:e.headers,queryParameters:h,hosts:o.map((function(e){return R(e)})),read:function(e,t){var r=m(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=i(e,2);return t[0],t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Write)})),e,m(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(o([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return h({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},A=function(e){return function(t,r){return t.method===F?e.transporter.read(t,r):e.transporter.write(t,r)}},H=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return h({transporter:e.transporter,appId:e.appId,indexName:t},r.methods)}},S=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{params:x(e.params||{})})}));return e.transporter.read({method:b,path:"1/indexes/*/queries",data:{requests:i},cacheable:!0},n)}},T=function(e){return function(t,i){return Promise.all(t.map((function(t){var a=t.params,s=a.facetName,c=a.facetQuery,u=n(a,["facetName","facetQuery"]);return H(e)(t.indexName,{methods:{searchForFacetValues:I}}).searchForFacetValues(s,c,r(r({},i),u))})))}},Q=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},C=function(e){return function(t,r){return e.transporter.read({method:b,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},I=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},k=1,D=2,q=3;function V(e,t,n){var i,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,i=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=i(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=i(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(i=q,{debug:function(e,t){return k>=i&&console.debug(e,t),Promise.resolve()},info:function(e,t){return D>=i&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:u(),requestsCache:u({serializable:!1}),hostsCache:c({caches:[s({key:"".concat("4.20.0","-").concat(e)}),u()]}),userAgent:_("4.20.0").add({segment:"Browser",version:"lite"}),authMode:l.WithinQueryParameters};return N(r(r(r({},a),n),{},{methods:{search:S,searchForFacetValues:T,multipleQueries:S,multipleSearchForFacetValues:T,customRequest:A,initIndex:function(e){return function(t){return H(e)(t,{methods:{search:C,searchForFacetValues:I,findAnswers:Q}})}}}}))}return V.version="4.20.0",V}()},6675:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>A});var n=r(7294),i=r(6010),a=r(8131),s=r.n(a),c=r(290),u=r.n(c),o=r(412),h=r(5742),f=r(9960),l=r(143),m=r(2263);const d=["zero","one","two","few","many","other"];function p(e){return d.filter((t=>e.includes(t)))}const v={locale:"en",pluralForms:p(["one","other"]),select:e=>1===e?"one":"other"};function g(){const{i18n:{currentLocale:e}}=(0,m.Z)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:p(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),v}}),[e])}function y(){const e=g();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const i=r.select(t),a=r.pluralForms.indexOf(i);return n[Math.min(a,n.length-1)]}(r,t,e)}}var R=r(6177),F=r(902),b=r(833),P=r(2128),j=r(5999),_=r(6278),E=r(239),x=r(7452);const O={searchQueryInput:"searchQueryInput_u2C7",searchVersionInput:"searchVersionInput_m0Ui",searchResultsColumn:"searchResultsColumn_JPFH",algoliaLogo:"algoliaLogo_rT1R",algoliaLogoPathFill:"algoliaLogoPathFill_WdUC",searchResultItem:"searchResultItem_Tv2o",searchResultItemHeading:"searchResultItemHeading_KbCB",searchResultItemPath:"searchResultItemPath_lhe1",searchResultItemSummary:"searchResultItemSummary_AEaO",searchQueryColumn:"searchQueryColumn_RTkw",searchVersionColumn:"searchVersionColumn_ypXd",searchLogoColumn:"searchLogoColumn_rJIA",loadingSpinner:"loadingSpinner_XVxU","loading-spin":"loading-spin_vzvp",loader:"loader_vvXV"};function w(e){let{docsSearchVersionsHelpers:t}=e;const r=Object.entries(t.allDocsData).filter((e=>{let[,t]=e;return t.versions.length>1}));return n.createElement("div",{className:(0,i.Z)("col","col--3","padding-left--none",O.searchVersionColumn)},r.map((e=>{let[i,a]=e;const s=r.length>1?`${i}: `:"";return n.createElement("select",{key:i,onChange:e=>t.setSearchVersion(i,e.target.value),defaultValue:t.searchVersions[i],className:O.searchVersionInput},a.versions.map(((e,t)=>n.createElement("option",{key:t,label:`${s}${e.label}`,value:e.name}))))})))}function N(){const{i18n:{currentLocale:e}}=(0,m.Z)(),{algolia:{appId:t,apiKey:r,indexName:a}}=(0,_.L)(),c=(0,E.l)(),d=function(){const{selectMessage:e}=y();return t=>e(t,(0,j.I)({id:"theme.SearchPage.documentsFound.plurals",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One document found|{count} documents found"},{count:t}))}(),p=function(){const e=(0,l._r)(),[t,r]=(0,n.useState)((()=>Object.entries(e).reduce(((e,t)=>{let[r,n]=t;return{...e,[r]:n.versions[0].name}}),{}))),i=Object.values(e).some((e=>e.versions.length>1));return{allDocsData:e,versioningEnabled:i,searchVersions:t,setSearchVersion:(e,t)=>r((r=>({...r,[e]:t})))}}(),[v,g]=(0,R.K)(),b={items:[],query:null,totalResults:null,totalPages:null,lastPage:null,hasMore:null,loading:null},[N,A]=(0,n.useReducer)(((e,t)=>{switch(t.type){case"reset":return b;case"loading":return{...e,loading:!0};case"update":return v!==t.value.query?e:{...t.value,items:0===t.value.lastPage?t.value.items:e.items.concat(t.value.items)};case"advance":{const t=e.totalPages>e.lastPage+1;return{...e,lastPage:t?e.lastPage+1:e.lastPage,hasMore:t}}default:return e}}),b),H=u()(t,r),S=s()(H,a,{hitsPerPage:15,advancedSyntax:!0,disjunctiveFacets:["language","docusaurus_tag"]});S.on("result",(e=>{let{results:{query:t,hits:r,page:n,nbHits:i,nbPages:a}}=e;if(""===t||!Array.isArray(r))return void A({type:"reset"});const s=e=>e.replace(/algolia-docsearch-suggestion--highlight/g,"search-result-match"),u=r.map((e=>{let{url:t,_highlightResult:{hierarchy:r},_snippetResult:n={}}=e;const i=Object.keys(r).map((e=>s(r[e].value)));return{title:i.pop(),url:c(t),summary:n.content?`${s(n.content.value)}...`:"",breadcrumbs:i}}));A({type:"update",value:{items:u,query:t,totalResults:i,totalPages:a,lastPage:n,hasMore:a>n+1,loading:!1}})}));const[T,Q]=(0,n.useState)(null),C=(0,n.useRef)(0),I=(0,n.useRef)(o.Z.canUseIntersectionObserver&&new IntersectionObserver((e=>{const{isIntersecting:t,boundingClientRect:{y:r}}=e[0];t&&C.current>r&&A({type:"advance"}),C.current=r}),{threshold:1})),k=()=>v?(0,j.I)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:v}):(0,j.I)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"}),D=(0,F.zX)((function(t){void 0===t&&(t=0),S.addDisjunctiveFacetRefinement("docusaurus_tag","default"),S.addDisjunctiveFacetRefinement("language",e),Object.entries(p.searchVersions).forEach((e=>{let[t,r]=e;S.addDisjunctiveFacetRefinement("docusaurus_tag",`docs-${t}-${r}`)})),S.setQuery(v).setPage(t).search()}));return(0,n.useEffect)((()=>{if(!T)return;const e=I.current;return e?(e.observe(T),()=>e.unobserve(T)):()=>!0}),[T]),(0,n.useEffect)((()=>{A({type:"reset"}),v&&(A({type:"loading"}),setTimeout((()=>{D()}),300))}),[v,p.searchVersions,D]),(0,n.useEffect)((()=>{N.lastPage&&0!==N.lastPage&&D(N.lastPage)}),[D,N.lastPage]),n.createElement(x.Z,null,n.createElement(h.Z,null,n.createElement("title",null,(0,P.p)(k())),n.createElement("meta",{property:"robots",content:"noindex, follow"})),n.createElement("div",{className:"container margin-vert--lg"},n.createElement("h1",null,k()),n.createElement("form",{className:"row",onSubmit:e=>e.preventDefault()},n.createElement("div",{className:(0,i.Z)("col",O.searchQueryColumn,{"col--9":p.versioningEnabled,"col--12":!p.versioningEnabled})},n.createElement("input",{type:"search",name:"q",className:O.searchQueryInput,placeholder:(0,j.I)({id:"theme.SearchPage.inputPlaceholder",message:"Type your search here",description:"The placeholder for search page input"}),"aria-label":(0,j.I)({id:"theme.SearchPage.inputLabel",message:"Search",description:"The ARIA label for search page input"}),onChange:e=>g(e.target.value),value:v,autoComplete:"off",autoFocus:!0})),p.versioningEnabled&&n.createElement(w,{docsSearchVersionsHelpers:p})),n.createElement("div",{className:"row"},n.createElement("div",{className:(0,i.Z)("col","col--8",O.searchResultsColumn)},!!N.totalResults&&d(N.totalResults)),n.createElement("div",{className:(0,i.Z)("col","col--4","text--right",O.searchLogoColumn)},n.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://www.algolia.com/","aria-label":(0,j.I)({id:"theme.SearchPage.algoliaLabel",message:"Search by Algolia",description:"The ARIA label for Algolia mention"})},n.createElement("svg",{viewBox:"0 0 168 24",className:O.algoliaLogo},n.createElement("g",{fill:"none"},n.createElement("path",{className:O.algoliaLogoPathFill,d:"M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"}),n.createElement("path",{fill:"#5468FF",d:"M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"}),n.createElement("path",{fill:"white",d:"M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"})))))),N.items.length>0?n.createElement("main",null,N.items.map(((e,t)=>{let{title:r,url:a,summary:s,breadcrumbs:c}=e;return n.createElement("article",{key:t,className:O.searchResultItem},n.createElement("h2",{className:O.searchResultItemHeading},n.createElement(f.Z,{to:a,dangerouslySetInnerHTML:{__html:r}})),c.length>0&&n.createElement("nav",{"aria-label":"breadcrumbs"},n.createElement("ul",{className:(0,i.Z)("breadcrumbs",O.searchResultItemPath)},c.map(((e,t)=>n.createElement("li",{key:t,className:"breadcrumbs__item",dangerouslySetInnerHTML:{__html:e}}))))),s&&n.createElement("p",{className:O.searchResultItemSummary,dangerouslySetInnerHTML:{__html:s}}))}))):[v&&!N.loading&&n.createElement("p",{key:"no-results"},n.createElement(j.Z,{id:"theme.SearchPage.noResultsText",description:"The paragraph for empty search result"},"No results were found")),!!N.loading&&n.createElement("div",{key:"spinner",className:O.loadingSpinner})],N.hasMore&&n.createElement("div",{className:O.loader,ref:Q},n.createElement(j.Z,{id:"theme.SearchPage.fetchingNewResults",description:"The paragraph for fetching new search results"},"Fetching new results..."))))}function A(){return n.createElement(b.FG,{className:"search-page-wrapper"},n.createElement(N,null))}}}]); \ No newline at end of file diff --git a/es/assets/js/1a4e3797.dd8146f2.js.LICENSE.txt b/es/assets/js/1a4e3797.dd8146f2.js.LICENSE.txt new file mode 100644 index 000000000000..8c17e740e697 --- /dev/null +++ b/es/assets/js/1a4e3797.dd8146f2.js.LICENSE.txt @@ -0,0 +1 @@ +/*! algoliasearch-lite.umd.js | 4.20.0 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */ diff --git a/es/assets/js/1be78505.dc6e92dc.js b/es/assets/js/1be78505.dc6e92dc.js new file mode 100644 index 000000000000..03b1e5894e38 --- /dev/null +++ b/es/assets/js/1be78505.dc6e92dc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[9514,4972],{9963:(e,t,n)=>{n.r(t),n.d(t,{default:()=>fe});var a=n(7294),l=n(6010),o=n(833),r=n(5281),c=n(3320),i=n(2802),s=n(4477),d=n(1116),m=n(7452),u=n(5999),b=n(2466),p=n(5936);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,l]=(0,a.useState)(!1),o=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.Ct)();return(0,b.RF)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(o.current?o.current=!1:a>=r?(c(),l(!1)):a{e.location.hash&&(o.current=!0,l(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,l.Z)("clean-btn",r.k.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(6550),g=n(7524),v=n(6668),_=n(1327),k=n(7462);function C(e){return a.createElement("svg",(0,k.Z)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const S={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function I(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,l.Z)("button button--secondary button--outline",S.collapseSidebarButton),onClick:t},a.createElement(C,{className:S.collapseSidebarButtonIcon}))}var N=n(9689),T=n(902);const x=Symbol("EmptyContext"),Z=a.createContext(x);function B(e){let{children:t}=e;const[n,l]=(0,a.useState)(null),o=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:l})),[n]);return a.createElement(Z.Provider,{value:o},t)}var y=n(6043),w=n(8596),L=n(9960),A=n(2389);function M(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function F(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,v.L)(),f=function(e){const t=(0,A.Z)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i.Wl)(e):void 0),[e,t])}(t),g=(0,i._F)(t,o),_=(0,w.Mg)(h,o),{collapsed:C,setCollapsed:S}=(0,y.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:I,setExpandedItem:N}=function(){const e=(0,a.useContext)(Z);if(e===x)throw new T.i6("DocSidebarItemsExpandedStateProvider");return e}(),B=function(e){void 0===e&&(e=!C),N(e?null:s),S(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:l}=e;const o=(0,T.D9)(t);(0,a.useEffect)((()=>{t&&!o&&n&&l(!1)}),[t,o,n,l])}({isActive:g,collapsed:C,updateCollapsed:B}),(0,a.useEffect)((()=>{b&&null!=I&&I!==s&&E&&S(!0)}),[b,I,s,S,E]),a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemCategory,r.k.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":C},p)},a.createElement("div",{className:(0,l.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":_})},a.createElement(L.Z,(0,k.Z)({className:(0,l.Z)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?B(!1):(e.preventDefault(),B())}:()=>{n?.(t)},"aria-current":_?"page":void 0,"aria-expanded":b?!C:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(M,{categoryLabel:u,onClick:e=>{e.preventDefault(),B()}})),a.createElement(y.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:C},a.createElement(K,{items:m,tabIndex:C?-1:0,onItemClick:n,activePath:o,level:c+1})))}var H=n(3919),P=n(9471);const W={menuExternalLink:"menuExternalLink_NmtK"};function D(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i._F)(t,o),E=(0,H.Z)(m);return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(L.Z,(0,k.Z)({className:(0,l.Z)("menu__link",!E&&W.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(P.Z,null)))}const R={menuHtmlItem:"menuHtmlItem_M9Kj"};function V(e){let{item:t,level:n,index:o}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(n),i&&[R.menuHtmlItem,"menu__list-item"],s),key:o,dangerouslySetInnerHTML:{__html:c}})}function z(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(F,(0,k.Z)({item:t},n));case"html":return a.createElement(V,(0,k.Z)({item:t},n));default:return a.createElement(D,(0,k.Z)({item:t},n))}}function U(e){let{items:t,...n}=e;return a.createElement(B,null,t.map(((e,t)=>a.createElement(z,(0,k.Z)({key:t,item:e,index:t},n)))))}const K=(0,a.memo)(U),j={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function q(e){let{path:t,sidebar:n,className:o}=e;const c=function(){const{isActive:e}=(0,N.nT)(),[t,n]=(0,a.useState)(e);return(0,b.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{"aria-label":(0,u.I)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,l.Z)("menu thin-scrollbar",j.menu,c&&j.menuWithAnnouncementBar,o)},a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:n,activePath:t,level:1})))}const G="sidebar_njMd",Y="sidebarWithHideableNavbar_wUlq",O="sidebarHidden_VK0M",X="sidebarLogo_isFc";function J(e){let{path:t,sidebar:n,onCollapse:o,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,v.L)();return a.createElement("div",{className:(0,l.Z)(G,c&&Y,r&&O)},c&&a.createElement(_.Z,{tabIndex:-1,className:X}),a.createElement(q,{path:t,sidebar:n}),i&&a.createElement(I,{onClick:o}))}const Q=a.memo(J);var $=n(3102),ee=n(3163);const te=e=>{let{sidebar:t,path:n}=e;const o=(0,ee.e)();return a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&o.toggle(),"link"===e.type&&o.toggle()},level:1}))};function ne(e){return a.createElement($.Zo,{component:te,props:e})}const ae=a.memo(ne);function le(e){const t=(0,g.i)(),n="desktop"===t||"ssr"===t,l="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(Q,e),l&&a.createElement(ae,e))}const oe={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function re(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:oe.expandButton,title:(0,u.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(C,{className:oe.expandButtonIcon}))}const ce={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry",sidebarViewport:"sidebarViewport_Xe31"};function ie(e){let{children:t}=e;const n=(0,d.V)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function se(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:o}=e;const{pathname:c}=(0,f.TH)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),o((e=>!e))}),[o,i]);return a.createElement("aside",{className:(0,l.Z)(r.k.docs.docSidebarContainer,ce.docSidebarContainer,n&&ce.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ce.docSidebarContainer)&&n&&s(!0)}},a.createElement(ie,null,a.createElement("div",{className:(0,l.Z)(ce.sidebarViewport,i&&ce.sidebarViewportHidden)},a.createElement(le,{sidebar:t,path:c,onCollapse:d,isHidden:i}),i&&a.createElement(re,{toggleSidebar:d}))))}const de={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function me(e){let{hiddenSidebarContainer:t,children:n}=e;const o=(0,d.V)();return a.createElement("main",{className:(0,l.Z)(de.docMainContainer,(t||!o)&&de.docMainContainerEnhanced)},a.createElement("div",{className:(0,l.Z)("container padding-top--md padding-bottom--lg",de.docItemWrapper,t&&de.docItemWrapperEnhanced)},n))}const ue={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX"};function be(e){let{children:t}=e;const n=(0,d.V)(),[l,o]=(0,a.useState)(!1);return a.createElement(m.Z,{wrapperClassName:ue.docsWrapper},a.createElement(E,null),a.createElement("div",{className:ue.docPage},n&&a.createElement(se,{sidebar:n.items,hiddenSidebarContainer:l,setHiddenSidebarContainer:o}),a.createElement(me,{hiddenSidebarContainer:l},t)))}var pe=n(4972),he=n(197);function Ee(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(he.Z,{version:t.version,tag:(0,c.os)(t.pluginId,t.version)}),a.createElement(o.d,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function fe(e){const{versionMetadata:t}=e,n=(0,i.hI)(e);if(!n)return a.createElement(pe.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(Ee,e),a.createElement(o.FG,{className:(0,l.Z)(r.k.wrapper.docsPages,r.k.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.q,{version:t},a.createElement(d.b,{name:m,items:u},a.createElement(be,null,c)))))}},4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(7294),l=n(5999),o=n(833),r=n(7452);function c(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>c,q:()=>r});var a=n(7294),l=n(902);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/es/assets/js/1df93b7f.7f8f9032.js b/es/assets/js/1df93b7f.7f8f9032.js new file mode 100644 index 000000000000..39449cce25fe --- /dev/null +++ b/es/assets/js/1df93b7f.7f8f9032.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3237],{3808:(e,t,a)=>{a.r(t),a.d(t,{default:()=>g});var r=a(7462),n=a(9960),l=a(4996),s=a(2263),c=a(7452),i=a(6010),o=a(7294);const m={heroBanner:"heroBanner_qdFl",buttons:"buttons_AeoN",features:"features_cAfv",featureImage:"featureImage_wMIZ","hero--primary":"hero--primary_JQ01",button:"button_JGCe"},u=[{title:"Ethereal Engine Embraces The Web",imageUrl:"img/undraw_docusaurus_mountain.svg",description:o.createElement(o.Fragment,null,"Reach everyone. No app stores. Open Source. ",o.createElement("br",null),"Mobile - Desktop - Headsets")},{title:"Focus On What Matters",imageUrl:"img/undraw_docusaurus_tree.svg",description:o.createElement(o.Fragment,null,"A comprehensive studio, pipeline tools, endless immersive features.")},{title:"Built On Well Known Web Frameworks",imageUrl:"img/undraw_docusaurus_react.svg",description:o.createElement(o.Fragment,null,"Power your experiences immediately with React, Threejs, Feathers, Kubernetes, bitECS")}];function d(e){let{imageUrl:t,title:a,description:r}=e;const n=(0,l.Z)(t);return o.createElement("div",{className:(0,i.Z)("col col--4",m.feature)},n&&o.createElement("div",{className:"text--center"},o.createElement("img",{className:m.featureImage,src:n,alt:a})),o.createElement("h3",null,a),o.createElement("p",null,r))}function g(){const{siteConfig:e}=(0,s.Z)();return o.createElement(c.Z,{title:`${e.title}`,description:"Description will go into a meta tag in "},o.createElement("header",{className:(0,i.Z)("hero hero--primary",m.heroBanner)},o.createElement("div",{className:"container"},o.createElement("h1",{className:"hero__title"},e.title),o.createElement("p",{className:"hero__subtitle"},e.tagline),o.createElement("div",{className:m.buttons},o.createElement(n.Z,{className:(0,i.Z)("button button--outline button--secondary button--lg",m.getStarted),to:(0,l.Z)("docs/")},"Get Started")))),o.createElement("main",null,u&&u.length>0&&o.createElement("section",{className:m.features},o.createElement("div",{className:"container"},o.createElement("div",{className:"row"},u.map(((e,t)=>o.createElement(d,(0,r.Z)({key:t},e)))))))))}}}]); \ No newline at end of file diff --git a/es/assets/js/1f391b9e.75a9ca1a.js b/es/assets/js/1f391b9e.75a9ca1a.js new file mode 100644 index 000000000000..8c15df347a0b --- /dev/null +++ b/es/assets/js/1f391b9e.75a9ca1a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3085],{4247:(e,t,a)=>{a.r(t),a.d(t,{default:()=>d});var l=a(7294),n=a(6010),c=a(833),r=a(5281),m=a(7452),i=a(7432),s=a(9407);const o={mdxPageWrapper:"mdxPageWrapper_j9I6"};function d(e){const{content:t}=e,{metadata:{title:a,description:d,frontMatter:p}}=t,{wrapperClassName:g,hide_table_of_contents:_}=p;return l.createElement(c.FG,{className:(0,n.Z)(g??r.k.wrapper.mdxPages,r.k.page.mdxPage)},l.createElement(c.d,{title:a,description:d}),l.createElement(m.Z,null,l.createElement("main",{className:"container container--fluid margin-vert--lg"},l.createElement("div",{className:(0,n.Z)("row",o.mdxPageWrapper)},l.createElement("div",{className:(0,n.Z)("col",!_&&"col--8")},l.createElement("article",null,l.createElement(i.Z,null,l.createElement(t,null)))),!_&&t.toc.length>0&&l.createElement("div",{className:"col col--2"},l.createElement(s.Z,{toc:t.toc,minHeadingLevel:p.toc_min_heading_level,maxHeadingLevel:p.toc_max_heading_level}))))))}}}]); \ No newline at end of file diff --git a/es/assets/js/222ee964.1c0e3f8c.js b/es/assets/js/222ee964.1c0e3f8c.js new file mode 100644 index 000000000000..b0feebbf20be --- /dev/null +++ b/es/assets/js/222ee964.1c0e3f8c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[401],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/es/assets/js/24869598.944c76c9.js b/es/assets/js/24869598.944c76c9.js new file mode 100644 index 000000000000..0c1d946fa460 --- /dev/null +++ b/es/assets/js/24869598.944c76c9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3573],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>u});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 l(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 p=r.createContext({}),h=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},s=function(e){var t=h(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=h(n),c=a,u=m["".concat(p,".").concat(c)]||m[c]||d[c]||i;return n?r.createElement(u,l(l({ref:t},s),{},{components:n})):r.createElement(u,l({ref:t},s))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:a,l[1]=o;for(var h=2;h{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>o,toc:()=>h});var r=n(7462),a=(n(7294),n(3905));const i={},l="Release Helm Chart",o={unversionedId:"host/devops_deployment/release_helm_chart",id:"host/devops_deployment/release_helm_chart",title:"Release Helm Chart",description:"Following are the steps that needs to be taken in order to update etherealengine helm charts repo:",source:"@site/docs/1_host/2_devops_deployment/6_release_helm_chart.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/release_helm_chart",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/6_release_helm_chart.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Cluster Management",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes"},next:{title:"Upgrading Helm Release",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment"}},p={},h=[],s={toc:h},m="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"release-helm-chart"},"Release Helm Chart"),(0,a.kt)("p",null,"Following are the steps that needs to be taken in order to update etherealengine helm charts repo:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Have a checked-out copy of ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/EtherealEngine/ethereal-engine-helm"},"https://github.com/EtherealEngine/ethereal-engine-helm"),", set to the ",(0,a.kt)("inlineCode",{parentName:"li"},"gh-pages")," branch"),(0,a.kt)("li",{parentName:"ul"},"Have a checked-out copy of ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"https://github.com/EtherealEngine/ethereal-engine-ops"),", set to the ",(0,a.kt)("inlineCode",{parentName:"li"},"master")," branch"),(0,a.kt)("li",{parentName:"ul"},"Set working directory to local ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-ops")," folder"),(0,a.kt)("li",{parentName:"ul"},"Increase the version number in ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine/Chart.yaml")),(0,a.kt)("li",{parentName:"ul"},"Run ",(0,a.kt)("inlineCode",{parentName:"li"},"helm package etherealengine")),(0,a.kt)("li",{parentName:"ul"},"Run ",(0,a.kt)("inlineCode",{parentName:"li"},"helm repo index --url https://helm.etherealengine.org .")),(0,a.kt)("li",{parentName:"ul"},"Copy ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine-X.Y.Z.tgz")," that's generated to the root of the ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm")," repo, and make sure to ",(0,a.kt)("inlineCode",{parentName:"li"},"git add")," it."),(0,a.kt)("li",{parentName:"ul"},"Open ",(0,a.kt)("inlineCode",{parentName:"li"},"index.yaml"),". Under entries.xrengine, there should be an entry for the new version."),(0,a.kt)("li",{parentName:"ul"},"Copy that entry to ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm"),"'s ",(0,a.kt)("inlineCode",{parentName:"li"},"index.yaml"),", making sure to put it under the right ",(0,a.kt)("inlineCode",{parentName:"li"},"entries")," section; we've got ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine-builder")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"etherealengine")," in the same file, so pay attention to which one you're putting it in. Also make sure that the spacing/indentation matches the other entries."),(0,a.kt)("li",{parentName:"ul"},"Copy the ",(0,a.kt)("inlineCode",{parentName:"li"},"generated")," line from ",(0,a.kt)("inlineCode",{parentName:"li"},"index.yaml")," to ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm/index.yaml"),", overwriting the ",(0,a.kt)("inlineCode",{parentName:"li"},"generated")," line that's there."),(0,a.kt)("li",{parentName:"ul"},"Commit this, and push it to the ",(0,a.kt)("inlineCode",{parentName:"li"},"gh-pages")," branch of ",(0,a.kt)("inlineCode",{parentName:"li"},"ethereal-engine-helm"),". Within a couple of minutes, you should see the new version appear at ",(0,a.kt)("a",{parentName:"li",href:"https://helm.etherealengine.org/"},"https://helm.etherealengine.org/"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/271238cb.e0da372c.js b/es/assets/js/271238cb.e0da372c.js new file mode 100644 index 000000000000..124af90690e8 --- /dev/null +++ b/es/assets/js/271238cb.e0da372c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5003],{3905:(e,t,n)=>{n.d(t,{Zo:()=>g,kt:()=>m});var r=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 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||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},g=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,g=s(e,["components","mdxType","originalType","parentName"]),d=l(n),u=o,m=d["".concat(c,".").concat(u)]||d[u]||p[u]||i;return n?r.createElement(m,a(a({ref:t},g),{},{components:n})):r.createElement(m,a({ref:t},g))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:o,a[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={hide_table_of_contents:!0},a="Debugging Engine in WSL on Phone/Headset",s={unversionedId:"creator/testing/debugging_device_wsl",id:"creator/testing/debugging_device_wsl",title:"Debugging Engine in WSL on Phone/Headset",description:"This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11.",source:"@site/docs/2_creator/6_testing/5_debugging_device_wsl.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/debugging_device_wsl",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/5_debugging_device_wsl.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Debugging",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging"},next:{title:"Debugging Deployed Instanceservers (and other Kubernetes pods)",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers"}},c={},l=[],g={toc:l},d="wrapper";function p(e){let{components:t,...i}=e;return(0,o.kt)(d,(0,r.Z)({},g,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"debugging-engine-in-wsl-on-phoneheadset"},"Debugging Engine in WSL on Phone/Headset"),(0,o.kt)("p",null,"This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Ensure that your ",(0,o.kt)("inlineCode",{parentName:"p"},".env.local")," and database entries points to ",(0,o.kt)("inlineCode",{parentName:"p"},"localhost"),".")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Open a location i.e. ",(0,o.kt)("inlineCode",{parentName:"p"},"https://localhost:3000/location/apartment")," through Windows 11 chrome. It should work fine.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Connect your device (currently tested on Samsung S22 Ultra) with PC and enabled USB debugging and access prompts as mentioned on ",(0,o.kt)("a",{parentName:"p",href:"https://developer.chrome.com/docs/devtools/remote-debugging/"},"https://developer.chrome.com/docs/devtools/remote-debugging/"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Once your device is connected, then you can see your device's browser tabs in PC's Chrome as show in below image. ",(0,o.kt)("inlineCode",{parentName:"p"},"chrome://inspect/#devices"),"\n",(0,o.kt)("img",{alt:"Device connected to PC Chrome",src:n(1086).Z,width:"1166",height:"540"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Make sure the check boxes marked in below are checked.\n",(0,o.kt)("img",{alt:"Remote Devtool Options",src:n(4021).Z,width:"865",height:"473"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},'Click on "Port forwarding" button and ensure you have entries as shown in below image. Also make sure to check the port forwarding checkbox in that modal.\n',(0,o.kt)("img",{alt:"Port Forwarding Options",src:n(7615).Z,width:"522",height:"444"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Once this is done and you have Port forwardings having green circles before them which means forwarding is working as shown in below image.\n",(0,o.kt)("img",{alt:"Port Forwarding Enabled",src:n(6253).Z,width:"1092",height:"504"}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Navigate to ",(0,o.kt)("inlineCode",{parentName:"p"},"https://localhost:3000/location/apartment")," in your device's browser.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"On your PC you can inspect this and allow if you face any certificate errors as shown in below image.\n",(0,o.kt)("img",{alt:"Remote Debugging",src:n(9764).Z,width:"1919",height:"1033"})))))}p.isMDXComponent=!0},1086:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_1-db578454e478384a8f5896f93530f0fe.png"},4021:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_2-41a58d269748d0ffce692c73a84530e9.png"},7615:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_3-188460f0a293898906be512799e62be2.png"},6253:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_4-8c79f91da94c7664b5191cefbf9b4fae.png"},9764:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debugging_device_wsl_5-70ba778cf0114bf6a6b6bda743434562.png"}}]); \ No newline at end of file diff --git a/es/assets/js/272.9b1a0f8c.js b/es/assets/js/272.9b1a0f8c.js new file mode 100644 index 000000000000..45fbb0e4a2c3 --- /dev/null +++ b/es/assets/js/272.9b1a0f8c.js @@ -0,0 +1 @@ +(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[272],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>u,kt:()=>f});var o=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 a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},p=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),p=r,f=m["".concat(i,".").concat(p)]||m[p]||d[p]||a;return n?o.createElement(f,c(c({ref:t},u),{},{components:n})):o.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,c=new Array(a);c[0]=p;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[m]="string"==typeof e?e:r,c[1]=l;for(var s=2;s{"use strict";n.d(t,{Z:()=>u});var o=n(7462),r=n(7294),a=n(6010),c=n(5999),l=n(6668),i=n(9960);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function u(e){let{as:t,id:n,...u}=e;const{navbar:{hideOnScroll:m}}=(0,l.L)();if("h1"===t||!n)return r.createElement(t,(0,o.Z)({},u,{id:void 0}));const d=(0,c.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof u.children?u.children:n});return r.createElement(t,(0,o.Z)({},u,{className:(0,a.Z)("anchor",m?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,u.className),id:n}),u.children,r.createElement(i.Z,{className:"hash-link",to:`#${n}`,"aria-label":d,title:d},"\u200b"))}},7432:(e,t,n)=>{"use strict";n.d(t,{Z:()=>pe});var o=n(7294),r=n(3905),a=n(7462),c=n(5742);var l=n(2389),i=n(6010),s=n(2949),u=n(6668);function m(){const{prism:e}=(0,u.L)(),{colorMode:t}=(0,s.I)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var d=n(5281),p=n(7594),f=n.n(p);const h=/title=(?["'])(?.*?)\1/,g=/\{(?<range>[\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function v(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function b(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:r,metastring:a}=t;if(a&&g.test(a)){const e=a.match(g).groups.range;if(0===r.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${a}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=r[0].className,o=f()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return v(["js","jsBlock"],t);case"jsx":case"tsx":return v(["js","jsBlock","jsx"],t);case"html":return v(["js","jsBlock","html"],t);case"python":case"py":case"bash":return v(["bash"],t);case"markdown":case"md":return v(["html","jsx","bash"],t);default:return v(Object.keys(y),t)}}(o,r),l=n.split("\n"),i=Object.fromEntries(r.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(r.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(r.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(r.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p<l.length;){const e=l[p].match(c);if(!e){p+=1;continue}const t=e.slice(1).find((e=>void 0!==e));s[t]?i[s[t]].range+=`${p},`:u[t]?i[u[t]].start=p:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${p-1},`),l.splice(p,1)}n=l.join("\n");const d={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;f()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const E={codeBlockContainer:"codeBlockContainer_Ckt0"};function k(e){let{as:t,...n}=e;const r=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,r]=e;const a=t[o];a&&"string"==typeof r&&(n[a]=r)})),n}(m());return o.createElement(t,(0,a.Z)({},n,{style:r,className:(0,i.Z)(n.className,E.codeBlockContainer,d.k.common.codeBlock)}))}const N={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function C(e){let{children:t,className:n}=e;return o.createElement(k,{as:"pre",tabIndex:0,className:(0,i.Z)(N.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:N.codeBlockLines},t))}var L=n(902);const w={attributes:!0,characterData:!0,childList:!0,subtree:!0};function B(e,t){const[n,r]=(0,o.useState)(),a=(0,o.useCallback)((()=>{r(e.current?.closest("[role=tabpanel][hidden]"))}),[e,r]);(0,o.useEffect)((()=>{a()}),[a]),function(e,t,n){void 0===n&&(n=w);const r=(0,L.zX)(t),a=(0,L.Ql)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(r);return e&&t.observe(e,a),()=>t.disconnect()}),[e,r,a])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),a())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const x={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var T={Prism:n(7410).Z,theme:x};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 Z(){return Z=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},Z.apply(this,arguments)}var j=/\r\n|\r|\n/,_=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},H=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)};function S(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var A=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),O(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),r=e.styles.reduce((function(e,n){var o=n.languages,r=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=Z({},e[t],r);e[t]=n})),e}),o);return r.root=n,r.plain=Z({},n,{backgroundColor:null}),r}(e.theme,e.language):void 0;return t.themeDict=n})),O(this,"getLineProps",(function(e){var n=e.key,o=e.className,r=e.style,a=Z({},S(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),c=t.getThemeDict(t.props);return void 0!==c&&(a.style=c.plain),void 0!==r&&(a.style=void 0!==a.style?Z({},a.style,r):r),void 0!==n&&(a.key=n),o&&(a.className+=" "+o),a})),O(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,r=n.length,a=t.getThemeDict(t.props);if(void 0!==a){if(1===r&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===r&&!o)return a[n[0]];var c=o?{display:"inline-block"}:{},l=n.map((function(e){return a[e]}));return Object.assign.apply(Object,[c].concat(l))}})),O(this,"getTokenProps",(function(e){var n=e.key,o=e.className,r=e.style,a=e.token,c=Z({},S(e,["key","className","style","token"]),{className:"token "+a.types.join(" "),children:a.content,style:t.getStyleForToken(a),key:void 0});return void 0!==r&&(c.style=void 0!==c.style?Z({},c.style,r):r),void 0!==n&&(c.key=n),o&&(c.className+=" "+o),c})),O(this,"tokenize",(function(e,t,n,o){var r={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",r);var a=r.tokens=e.tokenize(r.code,r.grammar,r.language);return e.hooks.run("after-tokenize",r),a}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,r=e.children,a=this.getThemeDict(this.props),c=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],o=[0],r=[e.length],a=0,c=0,l=[],i=[l];c>-1;){for(;(a=o[c]++)<r[c];){var s=void 0,u=t[c],m=n[c][a];if("string"==typeof m?(u=c>0?u:["plain"],s=m):(u=H(u,m.type),m.alias&&(u=H(u,m.alias)),s=m.content),"string"==typeof s){var d=s.split(j),p=d.length;l.push({types:u,content:d[0]});for(var f=1;f<p;f++)_(l),i.push(l=[]),l.push({types:u,content:d[f]})}else c++,t.push(u),n.push(s),o.push(0),r.push(s.length)}c--,t.pop(),n.pop(),o.pop(),r.pop()}return _(l),i}(void 0!==c?this.tokenize(t,o,c,n):[o]),className:"prism-code language-"+n,style:void 0!==a?a.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(o.Component);const I=A,P={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function z(e){let{line:t,classNames:n,showLineNumbers:r,getLineProps:c,getTokenProps:l}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const s=c({line:t,className:(0,i.Z)(n,r&&P.codeLine)}),u=t.map(((e,t)=>o.createElement("span",(0,a.Z)({key:t},l({token:e,key:t})))));return o.createElement("span",s,r?o.createElement(o.Fragment,null,o.createElement("span",{className:P.codeLineNumber}),o.createElement("span",{className:P.codeLineContent},u)):u,o.createElement("br",null))}var M=n(5999);const D={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function W(e){let{code:t,className:n}=e;const[r,a]=(0,o.useState)(!1),c=(0,o.useRef)(void 0),l=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const o=document.createElement("textarea"),r=document.activeElement;o.value=e,o.setAttribute("readonly",""),o.style.contain="strict",o.style.position="absolute",o.style.left="-9999px",o.style.fontSize="12pt";const a=document.getSelection(),c=a.rangeCount>0&&a.getRangeAt(0);n.append(o),o.select(),o.selectionStart=0,o.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}o.remove(),c&&(a.removeAllRanges(),a.addRange(c)),r&&r.focus()}(t),a(!0),c.current=window.setTimeout((()=>{a(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),o.createElement("button",{type:"button","aria-label":r?(0,M.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,M.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,M.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.Z)("clean-btn",n,D.copyButton,r&&D.copyButtonCopied),onClick:l},o.createElement("span",{className:D.copyButtonIcons,"aria-hidden":"true"},o.createElement("svg",{className:D.copyButtonIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),o.createElement("svg",{className:D.copyButtonSuccessIcon,viewBox:"0 0 24 24"},o.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const R={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function V(e){let{className:t,onClick:n,isEnabled:r}=e;const a=(0,M.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,i.Z)("clean-btn",t,r&&R.wordWrapButtonEnabled),"aria-label":a,title:a},o.createElement("svg",{className:R.wordWrapButtonIcon,viewBox:"0 0 24 24","aria-hidden":"true"},o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function $(e){let{children:t,className:n="",metastring:r,title:c,showLineNumbers:l,language:s}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,u.L)(),f=s??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,g=m(),y=function(){const[e,t]=(0,o.useState)(!1),[n,r]=(0,o.useState)(!1),a=(0,o.useRef)(null),c=(0,o.useCallback)((()=>{const n=a.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[a,e]),l=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=a.current,n=e>t||a.current.querySelector("code").hasAttribute("style");r(n)}),[a]);return B(a,l),(0,o.useEffect)((()=>{l()}),[e,l]),(0,o.useEffect)((()=>(window.addEventListener("resize",l,{passive:!0}),()=>{window.removeEventListener("resize",l)})),[l]),{codeBlockRef:a,isEnabled:e,isCodeScrollable:n,toggle:c}}(),v=function(e){return e?.match(h)?.groups.title??""}(r)||c,{lineClassNames:E,code:C}=b(t,{metastring:r,language:f,magicComments:p}),L=l??function(e){return Boolean(e?.includes("showLineNumbers"))}(r);return o.createElement(k,{as:"div",className:(0,i.Z)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},v&&o.createElement("div",{className:N.codeBlockTitle},v),o.createElement("div",{className:N.codeBlockContent},o.createElement(I,(0,a.Z)({},T,{theme:g,code:C,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:r,getTokenProps:a}=e;return o.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,i.Z)(t,N.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,i.Z)(N.codeBlockLines,L&&N.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(z,{key:t,line:e,getLineProps:r,getTokenProps:a,classNames:E[t],showLineNumbers:L})))))})),o.createElement("div",{className:N.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&o.createElement(V,{className:N.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),o.createElement(W,{className:N.codeButton,code:C}))))}function q(e){let{children:t,...n}=e;const r=(0,l.Z)(),c=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof c?$:C;return o.createElement(i,(0,a.Z)({key:String(r)},n),c)}var F=n(9960);var U=n(6043);const G={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function Y(e){return!!e&&("SUMMARY"===e.tagName||Y(e.parentElement))}function Q(e,t){return!!e&&(e===t||Q(e.parentElement,t))}function X(e){let{summary:t,children:n,...r}=e;const c=(0,l.Z)(),s=(0,o.useRef)(null),{collapsed:u,setCollapsed:m}=(0,U.u)({initialState:!r.open}),[d,p]=(0,o.useState)(r.open),f=o.isValidElement(t)?t:o.createElement("summary",null,t??"Details");return o.createElement("details",(0,a.Z)({},r,{ref:s,open:d,"data-collapsed":u,className:(0,i.Z)(G.details,c&&G.isBrowser,r.className),onMouseDown:e=>{Y(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;Y(t)&&Q(t,s.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),f,o.createElement(U.z,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},o.createElement("div",{className:G.collapsibleContent},n)))}const J={details:"details_b_Ee"},K="alert alert--info";function ee(e){let{...t}=e;return o.createElement(X,(0,a.Z)({},t,{className:(0,i.Z)(K,J.details,t.className)}))}var te=n(2503);function ne(e){return o.createElement(te.Z,e)}const oe={containsTaskList:"containsTaskList_mC6p"};const re={img:"img_ev3q"};const ae="admonition_LlT9",ce="admonitionHeading_tbUL",le="admonitionIcon_kALy",ie="admonitionContent_S0QG";const se={note:{infimaClassName:"secondary",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:o.createElement(M.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:o.createElement(M.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:o.createElement(M.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 16 16"},o.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:o.createElement(M.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},ue={secondary:"note",important:"info",success:"tip",warning:"danger"};function me(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=o.Children.toArray(e),n=t.find((e=>o.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),r=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:r}}(e.children);return{...e,title:e.title??t,children:n}}const de={head:function(e){const t=o.Children.map(e.children,(e=>o.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...r}=e.props;return o.createElement(e.props.originalType,r)}return e}(e):e));return o.createElement(c.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return o.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,o.isValidElement)(e)&&t.includes(e.props?.mdxType)))?o.createElement("code",e):o.createElement(q,e)},a:function(e){return o.createElement(F.Z,e)},pre:function(e){return o.createElement(q,(0,o.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=o.Children.toArray(e.children),n=t.find((e=>o.isValidElement(e)&&"summary"===e.props?.mdxType)),r=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return o.createElement(ee,(0,a.Z)({},e,{summary:n}),r)},ul:function(e){return o.createElement("ul",(0,a.Z)({},e,{className:(t=e.className,(0,i.Z)(t,t?.includes("contains-task-list")&&oe.containsTaskList))}));var t},img:function(e){return o.createElement("img",(0,a.Z)({loading:"lazy"},e,{className:(t=e.className,(0,i.Z)(t,re.img))}));var t},h1:e=>o.createElement(ne,(0,a.Z)({as:"h1"},e)),h2:e=>o.createElement(ne,(0,a.Z)({as:"h2"},e)),h3:e=>o.createElement(ne,(0,a.Z)({as:"h3"},e)),h4:e=>o.createElement(ne,(0,a.Z)({as:"h4"},e)),h5:e=>o.createElement(ne,(0,a.Z)({as:"h5"},e)),h6:e=>o.createElement(ne,(0,a.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:r,icon:a}=me(e),c=function(e){const t=ue[e]??e,n=se[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),se.info)}(n),l=r??c.label,{iconComponent:s}=c,u=a??o.createElement(s,null);return o.createElement("div",{className:(0,i.Z)(d.k.common.admonition,d.k.common.admonitionType(e.type),"alert",`alert--${c.infimaClassName}`,ae)},o.createElement("div",{className:ce},o.createElement("span",{className:le},u),l),o.createElement("div",{className:ie},t))},mermaid:()=>null};function pe(e){let{children:t}=e;return o.createElement(r.Zo,{components:de},t)}},9407:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var o=n(7462),r=n(7294),a=n(6010),c=n(3743);const l={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},i="table-of-contents__link toc-highlight",s="table-of-contents__link--active";function u(e){let{className:t,...n}=e;return r.createElement("div",{className:(0,a.Z)(l.tableOfContents,"thin-scrollbar",t)},r.createElement(c.Z,(0,o.Z)({},n,{linkClassName:i,linkActiveClassName:s})))}},3743:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var o=n(7462),r=n(7294),a=n(6668);function c(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const o=n.slice(2,e.level);e.parentIndex=Math.max(...o),n[e.level]=t}));const o=[];return t.forEach((e=>{const{parentIndex:n,...r}=e;n>=0?t[n].children.push(r):o.push(r)})),o}function l(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:o}=e;return t.flatMap((e=>{const t=l({toc:e.children,minHeadingLevel:n,maxHeadingLevel:o});return function(e){return e.level>=n&&e.level<=o}(e)?[{...e,children:t}]:t}))}function i(e){const t=e.getBoundingClientRect();return t.top===t.bottom?i(e.parentNode):t}function s(e,t){let{anchorTopOffset:n}=t;const o=e.find((e=>i(e).top>=n));if(o){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(i(o))?o:e[e.indexOf(o)-1]??null}return e[e.length-1]??null}function u(){const e=(0,r.useRef)(0),{navbar:{hideOnScroll:t}}=(0,a.L)();return(0,r.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function m(e){const t=(0,r.useRef)(void 0),n=u();(0,r.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:o,linkActiveClassName:r,minHeadingLevel:a,maxHeadingLevel:c}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(o),l=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const o=[];for(let r=t;r<=n;r+=1)o.push(`h${r}.anchor`);return Array.from(document.querySelectorAll(o.join()))}({minHeadingLevel:a,maxHeadingLevel:c}),i=s(l,{anchorTopOffset:n.current}),u=e.find((e=>i&&i.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(r),e.classList.add(r),t.current=e):e.classList.remove(r)}(e,e===u)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,n])}function d(e){let{toc:t,className:n,linkClassName:o,isChild:a}=e;return t.length?r.createElement("ul",{className:a?void 0:n},t.map((e=>r.createElement("li",{key:e.id},r.createElement("a",{href:`#${e.id}`,className:o??void 0,dangerouslySetInnerHTML:{__html:e.value}}),r.createElement(d,{isChild:!0,toc:e.children,className:n,linkClassName:o}))))):null}const p=r.memo(d);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:i="table-of-contents__link",linkActiveClassName:s,minHeadingLevel:u,maxHeadingLevel:d,...f}=e;const h=(0,a.L)(),g=u??h.tableOfContents.minHeadingLevel,y=d??h.tableOfContents.maxHeadingLevel,v=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:o}=e;return(0,r.useMemo)((()=>l({toc:c(t),minHeadingLevel:n,maxHeadingLevel:o})),[t,n,o])}({toc:t,minHeadingLevel:g,maxHeadingLevel:y});return m((0,r.useMemo)((()=>{if(i&&s)return{linkClassName:i,linkActiveClassName:s,minHeadingLevel:g,maxHeadingLevel:y}}),[i,s,g,y])),r.createElement(p,(0,o.Z)({toc:v,className:n,linkClassName:i},f))}},7594:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,r,a]=t;if(o&&a){o=parseInt(o),a=parseInt(a);const e=o<a?1:-1;"-"!==r&&".."!==r&&"\u2025"!==r||(a+=e);for(let t=o;t!==a;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/es/assets/js/28d03809.1287b94d.js b/es/assets/js/28d03809.1287b94d.js new file mode 100644 index 000000000000..c3a3559d5e91 --- /dev/null +++ b/es/assets/js/28d03809.1287b94d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1423],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=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]||r;return n?o.createElement(m,i(i({ref:t},p),{},{components:n})):o.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[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,i[1]=s;for(var c=2;c<r;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3030:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const r={},i="Studio Overview",s={unversionedId:"creator/studio/readme",id:"creator/studio/readme",title:"Studio Overview",description:"Ethereal Engine Studio",source:"@site/docs/2_creator/2_studio/readme.md",sourceDirName:"2_creator/2_studio",slug:"/creator/studio/",permalink:"/etherealengine-docs/es/docs/creator/studio/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/2_studio/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Studio & Locations",permalink:"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations"},next:{title:"Asset Import Pipeline",permalink:"/etherealengine-docs/es/docs/creator/importing_assets/"}},l={},c=[{value:"1 Toolbar",id:"1-toolbar",level:2},{value:"1. File Menu",id:"1-file-menu",level:3},{value:"2: Advanced",id:"2-advanced",level:3},{value:"3. Active Instances",id:"3-active-instances",level:3},{value:"4. Transform Gizmo: Scale, Rotate, Move",id:"4-transform-gizmo--scale-rotate-move",level:3}],p={toc:c},d="wrapper";function h(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"studio-overview"},"Studio Overview"),(0,a.kt)("p",null,"Ethereal Engine Studio\nUI Overview\n",(0,a.kt)("img",{parentName:"p",src:"https://github.com/EtherealEngine/etherealengine-docs/assets/5104160/a26ad154-64f4-4681-a011-70af9f4213e1",alt:"image6"})),(0,a.kt)("p",null,"1: Toolbar"),(0,a.kt)("p",null,"2: Scene and File Directory "),(0,a.kt)("p",null,"3: Preview"),(0,a.kt)("p",null,"4: Viewport"),(0,a.kt)("p",null,"5: Hierarchy, Material Library, Node Graph"),(0,a.kt)("p",null,"6: Properties "),(0,a.kt)("p",null,"7: Assembly Menu"),(0,a.kt)("p",null,"8: User Profile "),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"1-toolbar"},"1 Toolbar"),(0,a.kt)("h3",{id:"1-file-menu"},"1. File Menu"),(0,a.kt)("p",null,"Create new scenes, import files, and save or export existing scenes. "),(0,a.kt)("h3",{id:"2-advanced"},"2: Advanced"),(0,a.kt)("p",null,"Toggle advanced options on Model or Avatar components.\nAdd and remove components in the Properties tab "),(0,a.kt)("h3",{id:"3-active-instances"},"3. Active Instances"),(0,a.kt)("p",null,"Active Instances shown here"),(0,a.kt)("h3",{id:"4-transform-gizmo--scale-rotate-move"},"4. Transform Gizmo: Scale, Rotate, Move"),(0,a.kt)("p",null," ","[ Y ]"," Scale\n","[ R ]"," Rotate\n","[ T ]"," Move"),(0,a.kt)("ol",{start:5},(0,a.kt)("li",{parentName:"ol"},"World Space or Object Space Transform - toggle to world or object\nSets your transform control to be oriented to the object(selection) or world\nWorld space relates to the entire scene\u2019s orientation\nObject space (your selection) relates to transforms made to a specific object in relationship to the world space")),(0,a.kt)("p",null,"[ Z ]"," Toggle World space or Object(Selection) space"),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Toggle Transform Pivot - modes: Selection, Center, Bottom, or Origin\nTo use, shift select objects, enter transform mode (Y, R, T), choose pivot type:\nSelection:the center pivot of the final asset you selected in the sequence\nCenter: a pivot that sits at an equal distance between all selections\nBottom: pivot that sits equally between all selections and at the bottom of your final selection in the sequence\nOrigin: sets pivot mode to the world origin (0,0,0)\n*it is recommended to use the Toggle Transform in conjunction with the World/Object Space transforms")),(0,a.kt)("p",null,"[ X ]"," Toggle between Selection, Center, or Bottom\n","[ E ]"," incrementally rotate around the Y axis, adopts the selected snapping degree value "),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Grid Snapping (toggle)\nTransform objects by a unit of measurement ","[.1 meters, .125 meters, 1 meter, 4 meters, etc]","\nRotate objects by a specific degrees ","[5o,10o, 20o, 90o, etc]")),(0,a.kt)("p",null,"[ C ]"," Toggle Snap Mode\n","[ E ]"," incrementally rotate around the Y axis, adopts the selected snapping degree value "),(0,a.kt)("ol",{start:8},(0,a.kt)("li",{parentName:"ol"},"Grid Visibility (toggle)\nSet grid spacing by meters")),(0,a.kt)("ol",{start:9},(0,a.kt)("li",{parentName:"ol"},"Render Mode\nHow you view materials in the Engine\n(Unlit, Lit, Shadows, Wireframe, Normals)")),(0,a.kt)("ol",{start:10},(0,a.kt)("li",{parentName:"ol"},"Preview Scene\nSpawns you into the scene ")),(0,a.kt)("ol",{start:11},(0,a.kt)("li",{parentName:"ol"},"Status (toggle)")),(0,a.kt)("p",null,"Show stats about the scene and gives you a clue as to how optimized your scene is\nMemory: Geometries, Textures\nRender: FPS, Frame Time, Calls(drawcalls), Triangles, Points, Lines"),(0,a.kt)("ol",{start:12},(0,a.kt)("li",{parentName:"ol"},"Helpers (toggle)\nView hidden information about your scene, ie: colliders ")),(0,a.kt)("ol",{start:13},(0,a.kt)("li",{parentName:"ol"},"Node Helpers (toggle)\nHelper geometry that helps components have visibility in the scene when inactive ")),(0,a.kt)("ol",{start:14},(0,a.kt)("li",{parentName:"ol"},"Take A Screenshot\nTakes a screenshot of your scene at the current view")),(0,a.kt)("p",null,"#2 Scene and File Directory "),(0,a.kt)("p",null,"Project Files\nContains all files associated with your project.\n.json files and various other file types in this menu are your project files and will show up automatically when you create a new scene."),(0,a.kt)("p",null,"Assets folder\nContains all assets you can import into your scene. When you use the Toolbar: File Menu to import files, they are delivered directly to the assets folder. To populate your scene simply drag them from the assets directly to your hierarchy.\nTip: Import may create a transform offset\nWhen some assets are loaded they automatically show up in the scene in the hierarchy and sometimes at an offset. Simply delete them from the hierarchy and re-drag them from your assets folder into your scene hierarchy to have them be set at home (0,0,0)"),(0,a.kt)("p",null,"#3 The Preview Panel\nThe preview panel allows you to preview certain files, currently supporting image, video and audio files "),(0,a.kt)("p",null,"#4 Viewport\nThe view of all things active inside your scene.\nObjects have the typical navigation controls\nX = red\nY = green\nZ = blue"),(0,a.kt)("p",null,"#5 Hierarchy & Material Library\nHierarchy\nThe scene Hierarchy contains all element currently in your scene (assets, lighting, items from the tool menu, etc)\nMaterial Library\nLocation of an assets materials and where you can select and edit them "),(0,a.kt)("p",null,"#6 Properties\nWhere you can access and edit detailed information about objects in your scene.\nSelect an object in the Hierarchy to view its Properties. This panel supports editing and adding actions to objects, ie: keying transforms, turning on animation tracks, looping motion, and adding components to objects "),(0,a.kt)("p",null,"Model URL\nShows the location of an object in your scene hierarchy "),(0,a.kt)("p",null,"Using the Advanced Tab (toolbar)\nBy activating the advanced tab from the toolbar you are able to add specific components to assets in your scene adding data to the entity.\nExplode objects that are imported as a collapsed group"),(0,a.kt)("p",null,"Types of Components "),(0,a.kt)("p",null,"#7 Assembly Menu"),(0,a.kt)("p",null,"Files\nModel\nCreates objects in the hierarchy. Drag a model from the assets folder into the URL box or drag assets directly from project files into the hierarchy\nVolumetric\nImport volumetric files. Accepts DRCS, UVOL, or Manifest Files, links to cloud hosting\nVideo\n2D plane accepts .mp4 .mkv .avi\nAudio\nImport audio clips, .mp3, .flac, .ogg, .wav, .m4a"),(0,a.kt)("p",null,"Scene Composition\nGround Plane\nCreate collision ground plane\nGroup\nCollection of models or assets\nAsset Prefab\nCreate prefabs from groups or objects that are saved to the assets folder. Saving requires specific naming: 'assetName'.xre.gltf\nCollider\nCreates a collision ball, cuboid, capsule, or cylinder to be manually placement"),(0,a.kt)("p",null,"Interaction\nSpawn Point\nA point where people will appear when they enter your scene\nPortal\nA portal to teleport a player to a port in a different location"),(0,a.kt)("p",null,"Lights\nHemisphere Light\nA light which illuminates the scene from directly overhead\nPoint Light\nA light which emits in all directions from a single point\nDirectional Light\nCreates a light that emits evenly in a single direction\nAmbient Light\nA combination of direct and indirect light, provides general lighting to all assets\nSpot Light\nCreates a light that shines in a specific direction"),(0,a.kt)("p",null,"Scripting\nInserts code into the scene by creating a new Entity Component System based on the provided .ts file"),(0,a.kt)("p",null,"FX\nOcean\nCube body of water\nParticle Emitter\nCreates a particle emitter\nCloud\nSprite based cloud volume\nWater\nCreates a circular water surface with ripple effect\nSpline\nCreate and customize curves"),(0,a.kt)("p",null,"Misc\nE-commerce shop\nCreate a shop, choose product from dropdown, click select product, click away, click back, select product item(.glb), select variant, select product, click away, click back, object will populate scene"),(0,a.kt)("p",null,"#8 User Profile",(0,a.kt)("br",{parentName:"p"}),"\n","Your Ethereal Engine account settings and linked account information"),(0,a.kt)("p",null,"The settings wheel icon allows you to turn up your scene resolution.\nIf you notice the scene looks blurry, go to the Graphics tab inside Settings and turn the Resolution tab all the way up."),(0,a.kt)("p",null,"Create a Project\nImport Assets\nYou can use the File menu to import assets or you can drag and drop them into the assets folder, when clicking and dragging notice a slight change in the color of the Engine, this signifies the engine is ready to ingest your file.\nImporting assets immediately creates them in the scene at an arbitrary location when imported via the viewport. It is recommended to delete that import and drag an asset directly from project files into the hierarchy to easily zero out your transforms.\nEthereal Engine accept the following file types"),(0,a.kt)("p",null,"3D Models .glb, .gltf\nImages .png, .tiff, .jpeg\nVolumetric DRCS, UVOL, Manifest Files on the Cloud\nVideos .mp4m, .mkv, .avi\nAudio .mp3, .mpeg, .m4a\nSave Project\nIn the File menu, click the save or save as button to save your scene\nSome projects require time to save so don't exit this window until a few minutes have passed\nEdit Materials\nEthereal Engine supports a PBR workflow and Vertex Colors\nPBR Workflow:\nDiffuse or Base Color Map\nMetalness Map\nRoughness Map\nNormal Map\nAmbient Occlusion (AO) Map\n*each of these loaded will represent one draw call, only use maps you absolutely need. You can drop the diffuse map and use our built in RGB color selector to save scene space."),(0,a.kt)("p",null,"Your asset materials are visible in the order below under the Material Library tab\nMaterial Library "),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Asset Name\nmaterial name\nmaterial name\nmaterial name")),(0,a.kt)("p",null,"Material Types:\nMeshBasicMaterial\nThis material is not affected by lights.\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=meshba#api/en/materials/MeshBasicMaterial"},"https://threejs.org/docs/?q=meshba#api/en/materials/MeshBasicMaterial")," \t\t\t "),(0,a.kt)("p",null,"MeshStandardMaterial\nA standard physically based material, using Metallic-Roughness workflow.\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial"},"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial")),(0,a.kt)("p",null,"MeshMatcapMaterial\nMeshMatcapMaterial is defined by a MatCap (or Lit Sphere) texture, which encodes the \t\t\tmaterial color and shading.\nMeshPhysicalMaterial\nAn extension of the MeshStandardMaterial, providing more advanced physically-based rendering\n(added properties include: Clearcoat, Physically-based transparency, Advanced reflectivity, and Sheen)\nMeshLambertMaterial\nA material for non-shiny surfaces, without specular highlights.\nMeshPhongMaterial\nA material for shiny surfaces with specular highlights.\nMeshToonMaterial\nA material implementing toon shading.\nShaderMaterial\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=shadermat#api/en/materials/ShaderMaterial"},"https://threejs.org/docs/?q=shadermat#api/en/materials/ShaderMaterial"),"\nShadowMaterial\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=shadow#api/en/materials/ShadowMaterial"},"https://threejs.org/docs/?q=shadow#api/en/materials/ShadowMaterial")),(0,a.kt)("p",null,"Saving Changes\nAnytime you make a change to a model, you need to save your change.\nThis includes edits to the Position, Rotation, Scale, Normals, UVs, Materials and Attributes.\nAfter making your edit, go to the hierarchy and re-select your asset, in the Properties tab, scroll to the bottom and click the Save Changes button. If you want to Save As, in the url just above the Save Changes button, you can manually edit the name at the end of the url and click Save Changes. You can find the new version of your .glbl in the assets folder. "),(0,a.kt)("p",null,"Tip: Convert .gltfs or .usdz to .glb format in the engine using this method\nCompression\nThe in-engine compression menu is available when you select the model you want to run compression on from the Hierarchy. Scrolling down inside of the Properties panel you can expand the Model Transform Properties Menu.\nThere are three menus, gltF-Transform, Delete Attributes, Bake To Vertices."),(0,a.kt)("p",null,"gltF-Compression:\nRuns compression on the models geometry and image textures. Default settings work well for most models.\nThe Image Format menu allows you to either choose JPG, KTX2, or PNG for the image\u2019s compression format.\nThe Max Texture Size denotes the pixel scale of your image. Default settings downsize the textures to 1024 pixels x 1024 pixels\nPress Optimize to run the compression"),(0,a.kt)("p",null,"Delete Attributes:\nModels occasionally are imported with an excess of attributes taking up unwanted space, to delete the extra, unnecessary data list the attributes here with a space in between each attribute listed"),(0,a.kt)("p",null,"Bake To Vertices:\nThis tool bakes your texture to vertex color. By doing this we can eliminate the need for loading heavy images on some models. Vertex Baking transfers your PBR maps to the vertex of your model. We currently support diffuse, lightMap and emissive.\n*this method is for models that have a simple texture with either a single color or few details"),(0,a.kt)("p",null,"Animations in Objects\nAvatars\nTo turn on the animations of an imported model you would like to use as an avatar, in the Loop Animation tab you can select the animation track you wish to activate, \u201cmixamo.com\u201d.\nLoop Animations: loop the motion tracks available on your avatar\nChecking \u2018Is Avatar\u2019 allows you to use the animations built into the engine on your Avatar. "),(0,a.kt)("p",null,"Animated Geometry\nLoop Animations: loop the motion tracks available on your model"),(0,a.kt)("p",null,"Skybox/Cubemap\nThe Skybox Button from the Tools Panel allows you to create a Skybox for your scene.\nYou can choose between Color, Skybox, Cubemap, and Equirectangular\nColor: basic color as the sky\nSkybox: cubemap that surrounds your scene giving the look of being in an environment\nEquirectangular: sphere that surrounds your scene giving the look of being in an environment, recommended sources for equirectangular images are hdrihaven.com or "),(0,a.kt)("p",null,"Tip: HdriHaven has great free HDRI Resources"),(0,a.kt)("p",null,"Importing individual models (.glb/.gltf & .usdz)\nImport your model via the File Menu or drag and drop into the Viewport (when viewport changes color it is ready to ingest the file)\nWith the model in your Hierarchy, select it and scroll down in its Properties tab.\nRe-name to your desired description with a .glb or .gltf extension. You can find your saved model in your Assets tab in the Project Files directory\nscene should be determined by what your scene is composed of. Successful optimization is achieved by leveraging the appropriate use of detail per model.\nConverting Models to .glb (recommended)\nConvert .gltf to a .glb (in browser)\nRecommended to convert .gltf into .glbs for easier importing\n",(0,a.kt)("a",{parentName:"p",href:"https://glb-packer.glitch.me/"},"https://glb-packer.glitch.me/"),"\n",(0,a.kt)("a",{parentName:"p",href:"https://cartmagician.com/tools/3d-to-AR-converter"},"https://cartmagician.com/tools/3d-to-AR-converter")," (paid)\nConvert .fbx to .glb (app)\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/facebookincubator/FBX2glTF"},"https://github.com/facebookincubator/FBX2glTF"),"\nConvert .usd to .gltf (in browser)\n",(0,a.kt)("a",{parentName:"p",href:"https://products.groupdocs.app/conversion/usd-to-gltf"},"https://products.groupdocs.app/conversion/usd-to-gltf")),(0,a.kt)("p",null,"Using SampleStandardMaterial to enhance projects\nCustom settings for Glass, Plastic, Glow & Metal are provided below"),(0,a.kt)("p",null,"For the MeshStandardMaterial\n(re-create values below to simulate materials on your geometry)\n",(0,a.kt)("a",{parentName:"p",href:"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial"},"https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial")),(0,a.kt)("p",null," Glass\t\t Plastic\t Glow\t\t\t Metal"),(0,a.kt)("p",null,"Tip: Exporting assets for basic materials\nIt is not required to have a texture map on all assets in 3D and it is recommended to use Standard Materials as often as possible. We recommended using basic materials for all basic metal, glass, emissive, and plastic assets (follow the sample material set-up above). You must denote which assets will have Standard Materials before you import your .glb to the engine. It is recommended to simply drag a native material from your chosen DCC or game engine prior to export, correctly name the basic material before exporting the .glb. Names given before import are the names the engine will inherit."),(0,a.kt)("p",null,"Saving Your Project "),(0,a.kt)("p",null,"Save As or Save Scene can be found in the File Menu.\nAllow the Engine a few minutes to save your file.\nTip: Change the view to create a thumbnail\nYou will be asked to create a thumbnail on Save which takes a screenshot from the current viewport view. Move your viewport to look at the desired view for your thumbnail before you click Save."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/291a898d.88c52616.js b/es/assets/js/291a898d.88c52616.js new file mode 100644 index 000000000000..966d6b9a149f --- /dev/null +++ b/es/assets/js/291a898d.88c52616.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2606],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(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 a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?l(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},l=Object.keys(e);for(n=0;n<l.length;n++)r=l[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n<l.length;n++)r=l[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var i=n.createContext({}),s=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,l=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),m=o,f=u["".concat(i,".").concat(m)]||u[m]||d[m]||l;return r?n.createElement(f,a(a({ref:t},p),{},{components:r})):n.createElement(f,a({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=r.length,a=new Array(l);a[0]=m;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[u]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<l;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},9871:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>d,frontMatter:()=>l,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const l={},a="Control Center App",c={unversionedId:"host/devops_deployment/tutorials/ethereal_control_center/readme",id:"host/devops_deployment/tutorials/ethereal_control_center/readme",title:"Control Center App",description:"In this section you will various tutorials for Ethereal Engine Control System app.",source:"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/readme.md",sourceDirName:"1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center",slug:"/host/devops_deployment/tutorials/ethereal_control_center/",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Tutorials",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/"},next:{title:"Getting Started",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started"}},i={},s=[],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"control-center-app"},"Control Center App"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine Control System app."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/33e7527e.bca6e6d3.js b/es/assets/js/33e7527e.bca6e6d3.js new file mode 100644 index 000000000000..f1e7da5c4b75 --- /dev/null +++ b/es/assets/js/33e7527e.bca6e6d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2984],{7085:e=>{e.exports=JSON.parse('{"name":"docusaurus-theme-search-algolia","id":"default"}')}}]); \ No newline at end of file diff --git a/es/assets/js/393be207.6e6ea16e.js b/es/assets/js/393be207.6e6ea16e.js new file mode 100644 index 000000000000..3b5a5e4a9d52 --- /dev/null +++ b/es/assets/js/393be207.6e6ea16e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7414],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 p(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),i=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):p(p({},t),e)),r},u=function(e){var t=i(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=i(r),m=o,d=s["".concat(l,".").concat(m)]||s[m]||f[m]||a;return r?n.createElement(d,p(p({ref:t},u),{},{components:r})):n.createElement(d,p({ref:t},u))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,p=new Array(a);p[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:o,p[1]=c;for(var i=2;i<a;i++)p[i]=r[i];return n.createElement.apply(null,p)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},3123:(e,t,r)=>{r.r(t),r.d(t,{contentTitle:()=>p,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={title:"Markdown page example"},p="Markdown page example",c={type:"mdx",permalink:"/etherealengine-docs/es/markdown-page",source:"@site/src/pages/markdown-page.md",title:"Markdown page example",description:"You don't need React to write simple standalone pages.",frontMatter:{title:"Markdown page example"}},l=[],i={toc:l},u="wrapper";function s(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},i,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"markdown-page-example"},"Markdown page example"),(0,o.kt)("p",null,"You don't need React to write simple standalone pages."))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/3c3cda30.3166b617.js b/es/assets/js/3c3cda30.3166b617.js new file mode 100644 index 000000000000..17bc1731c62b --- /dev/null +++ b/es/assets/js/3c3cda30.3166b617.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[9037],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function l(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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){l(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,l=function(e,t){if(null==e)return{};var n,a,l={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},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,l=e.mdxType,o=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),p=c(n),m=l,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,i=new Array(o);i[0]=m;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[p]="string"==typeof e?e:l,i[1]=r;for(var c=2;c<o;c++)i[c]=n[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7360:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var a=n(7462),l=(n(7294),n(3905)),o=n(4401);const i={},r="Ethereal Engine on MicroK8s (Windows)",s={unversionedId:"host/devops_deployment/microk8s_windows",id:"host/devops_deployment/microk8s_windows",title:"Ethereal Engine on MicroK8s (Windows)",description:"This guide is intended for local environment and currently tested on Windows 11.",source:"@site/docs/1_host/2_devops_deployment/0_microk8s_windows.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/microk8s_windows",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/0_microk8s_windows.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on MicroK8s (Linux)",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux"},next:{title:"Ethereal Engine on Docker Desktop",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop"}},c={},u=[{value:"Install Windows Subsystem for Linux (WSL)",id:"install-windows-subsystem-for-linux-wsl",level:2},{value:"Set Ubuntu as default WSL distribution",id:"set-ubuntu-as-default-wsl-distribution",level:3},{value:"Install Docker Desktop",id:"install-docker-desktop",level:2},{value:"Enable systemd in WSL",id:"enable-systemd-in-wsl",level:2},{value:"Enable localhostForwarding in WSL",id:"enable-localhostforwarding-in-wsl",level:2},{value:"Install Node",id:"install-node",level:2},{value:"Install Python 3",id:"install-python-3",level:2},{value:"Install Make",id:"install-make",level:2},{value:"Install kubectl and Helm",id:"install-kubectl-and-helm",level:2},{value:"Download and install MicroK8s",id:"download-and-install-microk8s",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Enabling MicroK8s Addons",id:"enabling-microk8s-addons",level:2},{value:"Add MicroK8s to Kubectl",id:"add-microk8s-to-kubectl",level:2},{value:"(Optional) Add MicroK8s to Lens",id:"optional-add-microk8s-to-lens",level:2},{value:"Enable MicroK8s access for local docker",id:"enable-microk8s-access-for-local-docker",level:2},{value:"Verify and troubleshoot MicroK8s",id:"verify-and-troubleshoot-microk8s",level:2},{value:"Update system hostfile to point to MicroK8s",id:"update-system-hostfile-to-point-to-microk8s",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"(Optional) Install Elastic Search and Kibana using Helm for Server Logs",id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Run build_microk8s.sh",id:"run-build_microk8ssh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],p={toc:u},d="wrapper";function m(e){let{components:t,...i}=e;return(0,l.kt)(d,(0,a.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"ethereal-engine-on-microk8s-windows"},"Ethereal Engine on MicroK8s (Windows)"),(0,l.kt)("p",null,"This guide is intended for local environment and currently tested on Windows 11."),(0,l.kt)("h2",{id:"install-windows-subsystem-for-linux-wsl"},"Install Windows Subsystem for Linux (WSL)"),(0,l.kt)("p",null,"Install Ubuntu distribution of Linux from Microsoft Store by using guide ",(0,l.kt)("a",{parentName:"p",href:"https://learn.microsoft.com/en-us/windows/wsl/install"},"here"),"."),(0,l.kt)("p",null,"Alternatively, you can follow these instructions as well:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://pureinfotech.com/install-wsl-windows-11/"},"How to install WSL")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/install-manual"},"Manual installation steps for WSL"))),(0,l.kt)("p",null,"Once WSL is installed, make sure to:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#set-up-your-linux-username-and-password"},"Set up your Linux username and password")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://learn.microsoft.com/en-us/windows/wsl/setup/environment#update-and-upgrade-packages"},"Update and upgrade packages"))),(0,l.kt)("h3",{id:"set-ubuntu-as-default-wsl-distribution"},"Set Ubuntu as default WSL distribution"),(0,l.kt)("p",null,"In powershell/cmd run following command to see the list of distributions:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"wsl -l\n")),(0,l.kt)("p",null,"In the list you should be able to see ",(0,l.kt)("inlineCode",{parentName:"p"},"Ubuntu")," listed. Afterwards, run following command to set Ubuntu as default distribution:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"wsl -s Ubuntu\n")),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"WSL Ubuntu Default Distribution",src:n(8488).Z,width:"769",height:"435"})),(0,l.kt)("h2",{id:"install-docker-desktop"},"Install Docker Desktop"),(0,l.kt)("p",null,"Install docker desktop with WSL 2 backend. You can find the instructions ",(0,l.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/windows-install/"},"here"),"."),(0,l.kt)("p",null,"Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting ",(0,l.kt)("inlineCode",{parentName:"p"},"Settings > Resources > WSL Integration"),". Make sure to hit 'Apply & Restart'."),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"Docker Desktop WSL Distro",src:n(5238).Z,width:"1918",height:"1033"})),(0,l.kt)("h2",{id:"enable-systemd-in-wsl"},"Enable systemd in WSL"),(0,l.kt)("p",null,"Inside your Ubuntu instance, add the following modification to ",(0,l.kt)("inlineCode",{parentName:"p"},"/etc/wsl.conf"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-conf"},"[boot]\nsystemd=true\n")),(0,l.kt)("p",null,"Then restart your instance by running ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl --shutdown")," in PowerShell and relaunching Ubuntu. Upon launch you should have systemd running. You can check this with the command ",(0,l.kt)("inlineCode",{parentName:"p"},"systemctl list-unit-files --type=service")," which should show your services status."),(0,l.kt)("p",null,"You can read more about this on ",(0,l.kt)("a",{parentName:"p",href:"https://ubuntu.com/blog/ubuntu-wsl-enable-systemd"},"Ubuntu blog")," & ",(0,l.kt)("a",{parentName:"p",href:"https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/"},"Microsoft blog"),"."),(0,l.kt)("h2",{id:"enable-localhostforwarding-in-wsl"},"Enable localhostForwarding in WSL"),(0,l.kt)("p",null,"Create or update ",(0,l.kt)("inlineCode",{parentName:"p"},".wslconfig")," file located at ",(0,l.kt)("inlineCode",{parentName:"p"},"C:\\Users\\{USER_NAME}\\.wslconfig")," (Or ",(0,l.kt)("inlineCode",{parentName:"p"},"%UserProfile%\\.wslconfig"),") with following content:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-conf"},"[wsl2]\nlocalhostForwarding=true\n")),(0,l.kt)("p",null,"This requires WSL shutdown and reboot. Shutting down your terminal is insufficient. Also machine boot is not required. Simply run:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"wsl --shutdown (in Powershell) or \nwsl.exe --shutdown (within Ubuntu)\n")),(0,l.kt)("p",null,"Reference: ",(0,l.kt)("a",{parentName:"p",href:"https://stackoverflow.com/a/65707003/2077741"},"Custom hostname for servers running in WSL 2")),(0,l.kt)("h2",{id:"install-node"},"Install Node"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if node (",(0,l.kt)("inlineCode",{parentName:"p"},"node --version"),") isn't already installed on your machine. You can do so by first installing ",(0,l.kt)("inlineCode",{parentName:"p"},"nvm")," by running following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash\nsource ~/.profile\n\nexport NVM_DIR="$HOME/.nvm"\n[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh" # This loads nvm\n[ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n')),(0,l.kt)("p",null,"You can verify nvm by using ",(0,l.kt)("inlineCode",{parentName:"p"},"nvm --version")," command. Afterwards, install node by using:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"nvm install --lts\n")),(0,l.kt)("p",null,"You can verify nvm by using ",(0,l.kt)("inlineCode",{parentName:"p"},"node --version")," command."),(0,l.kt)("h2",{id:"install-python-3"},"Install Python 3"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if python 3 (",(0,l.kt)("inlineCode",{parentName:"p"},"pip3 --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y python3-pip\n")),(0,l.kt)("p",null,"You can verify python3 by using ",(0,l.kt)("inlineCode",{parentName:"p"},"python3 --version")," command."),(0,l.kt)("h2",{id:"install-make"},"Install Make"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if make (",(0,l.kt)("inlineCode",{parentName:"p"},"make --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y build-essential\n")),(0,l.kt)("p",null,"You can verify make by using ",(0,l.kt)("inlineCode",{parentName:"p"},"make --version")," command."),(0,l.kt)("h2",{id:"install-kubectl-and-helm"},"Install kubectl and Helm"),(0,l.kt)("p",null,"In your WSL Ubuntu terminal, if ",(0,l.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl")," & ",(0,l.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm")," aren't already installed on your machine, install them."),(0,l.kt)("p",null,'Docker & Docker Compose should be installed if you successfully completed "',(0,l.kt)("a",{parentName:"p",href:"#install-docker-desktop"},"Install Docker Desktop"),'" step. You can verify by running ',(0,l.kt)("inlineCode",{parentName:"p"},"docker --version")," & ",(0,l.kt)("inlineCode",{parentName:"p"},"docker-compose --version")," commands in WSL Ubuntu terminal."),(0,l.kt)("h2",{id:"download-and-install-microk8s"},"Download and install MicroK8s"),(0,l.kt)("p",null,"Make sure to install MicroK8s in your WSL Ubuntu terminal. Instructions can be found ",(0,l.kt)("a",{parentName:"p",href:"https://ubuntu.com/tutorials/install-a-local-kubernetes-with-microk8s#1-overview"},"here")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo snap install microk8s --classic --channel=1.26/stable\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.")),(0,l.kt)("p",null,"While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it."),(0,l.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,l.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/etherealengine/etherealengine.git etherealengine\n")),(0,l.kt)("p",null,"If ",(0,l.kt)("inlineCode",{parentName:"p"},".env.local")," file does not exist in the root of your repo folder then create it by duplicating ",(0,l.kt)("inlineCode",{parentName:"p"},".env.local.default"),"."),(0,l.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,l.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,l.kt)("p",null,"If you run ",(0,l.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,l.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,l.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,l.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,l.kt)("inlineCode",{parentName:"p"},"./scripts/build_microk8s.sh"),"."),(0,l.kt)("h2",{id:"enabling-microk8s-addons"},"Enabling MicroK8s Addons"),(0,l.kt)("p",null,"Execute following command in your WSL Ubuntu terminal to enable MicroK8s addons"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3\n")),(0,l.kt)("h2",{id:"add-microk8s-to-kubectl"},"Add MicroK8s to Kubectl"),(0,l.kt)("p",null,"First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command in WSL Ubuntu terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config delete-context microk8s\nkubectl config delete-cluster microk8s-cluster\nkubectl config delete-user microk8s-admin\n")),(0,l.kt)("p",null,"Now, we will add microk8s configuration to kubectl config. We can do this by using following commands in WSL Ubuntu terminal. ",(0,l.kt)("a",{parentName:"p",href:"https://discuss.kubernetes.io/t/use-kubectl-with-microk8s/5313/6"},"Reference")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt\nkubectl config set-credentials microk8s-admin --token=\"$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')\"\nkubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin\n")),(0,l.kt)("p",null,"Afterwards you can use this newly create context by executing:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config use-context microk8s\n")),(0,l.kt)("p",null,"Now if you run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command then microk8s should be current context."),(0,l.kt)("h2",{id:"optional-add-microk8s-to-lens"},"(Optional) Add MicroK8s to Lens"),(0,l.kt)("p",null," If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool ",(0,l.kt)("a",{parentName:"p",href:"https://k8slens.dev/"},"Lens"),". Else you can print the configuration using following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"microk8s config\n")),(0,l.kt)("p",null,"In Lens, goto ",(0,l.kt)("inlineCode",{parentName:"p"},"File")," > ",(0,l.kt)("inlineCode",{parentName:"p"},"Add Cluster")," and paste the output of above command to add cluster."),(0,l.kt)("h2",{id:"enable-microk8s-access-for-local-docker"},"Enable MicroK8s access for local docker"),(0,l.kt)("p",null,"For MicroK8s we will be using MicroK8s local ",(0,l.kt)("a",{parentName:"p",href:"https://microk8s.io/docs/registry-built-in"},"registry")),(0,l.kt)("p",null,"Option 1: In Windows, add the following lines to ",(0,l.kt)("inlineCode",{parentName:"p"},"%userprofile%\\.docker\\daemon.json"),". Create this file if it does not already exists."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-json"},'{ \n "insecure-registries" : ["http://microk8s.registry:32000", "microk8s.registry:32000"] \n}\n')),(0,l.kt)("p",null,"Afterwards, restart docker from Powershell: ",(0,l.kt)("inlineCode",{parentName:"p"},"restart-service *docker*")),(0,l.kt)("p",null,"Option 2: Edit configuration as shown in below image. Make sure to hit 'Apply & Restart' after making changes."),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"Docker Desktop Configuration",src:n(7233).Z,width:"1920",height:"1030"})),(0,l.kt)("p",null,"Reference:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://stackoverflow.com/a/55352883/2077741"},"daemon.json file in W1indows")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/docker/docs/blob/62adddbb6b1f8d861c72f6ade2c50977fd57f481/registry/insecure.md#troubleshoot-insecure-registry"},"When using buildkit, http needs to be added")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://forums.docker.com/t/restart-docker-service-from-command-line/27331/2"},"Restart Docker service from command line"))),(0,l.kt)("h2",{id:"verify-and-troubleshoot-microk8s"},"Verify and troubleshoot MicroK8s"),(0,l.kt)("p",null,"Run following command and check if there is any warning. Its recommended to fix the warnings for MicroK8s to work properly."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo microk8s inspect\n")),(0,l.kt)("h2",{id:"update-system-hostfile-to-point-to-microk8s"},"Update system hostfile to point to MicroK8s"),(0,l.kt)("p",null,"You'll need to edit your hostfile to point certain domains to host machine IP address. First you need to find the IP address of your WSL. Run ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl hostname -I")," in powershell/cmd. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"C:\\Users\\hanzl>wsl hostname -I\n172.31.89.133 10.1.215.0\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Note: If you face issue while running above command, make sure that 'Ubuntu' distribution is selected as default. You can do so by running ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl /l")," to view distributions and then run ",(0,l.kt)("inlineCode",{parentName:"p"},"wslconfig /s Ubuntu")," to select distribution.")),(0,l.kt)("p",null,"From the above output, use ",(0,l.kt)("inlineCode",{parentName:"p"},"172.31.89.133")," as ",(0,l.kt)("inlineCode",{parentName:"p"},"{WSL_IP}"),"."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Note: Your ip would be different, this is just for example.")),(0,l.kt)("p",null,"Next, edit your Windows hostfile, this is done by editing ",(0,l.kt)("inlineCode",{parentName:"p"},"C:\\Windows\\System32\\drivers\\etc\\hosts"),". Add/Update the following lines:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-conf"},"{WSL_IP} local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org\n\n{WSL_IP} microk8s.registry\n")),(0,l.kt)("p",null,"Make sure to replace ",(0,l.kt)("inlineCode",{parentName:"p"},"{WSL_IP}")," with ip address from ",(0,l.kt)("inlineCode",{parentName:"p"},"wsl hostname -I")," command."),(0,l.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod."),(0,l.kt)("p",null,"Make sure to save this file after you've edited it. Also, you will need to update hostfile with updated ip address after every Windows/WSL reboot."),(0,l.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,l.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,l.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,l.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,l.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,l.kt)("p",null,"Make sure that kubectl is pointed at MicroK8s by running ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),", which should say 'microk8s'. You can also run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,l.kt)("p",null,"Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones and ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("p",null,"You can run ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state."),(0,l.kt)("h2",{id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs"},"(Optional) Install Elastic Search and Kibana using Helm for Server Logs"),(0,l.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,l.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,l.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,l.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,l.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,l.kt)("p",null,"Now check if the cluster members are up: ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,l.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,l.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,l.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,l.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana")),(0,l.kt)("p",null,"Check if all the pods are ready: ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,l.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,l.kt)("inlineCode",{parentName:"p"},"http://localhost:5601")," in your browser"),(0,l.kt)("p",null,"In order to connect logger with elasticsearch, update ",(0,l.kt)("inlineCode",{parentName:"p"},"local.microk8s.template.values.yaml")," env ",(0,l.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"local.microk8s.template.values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("h2",{id:"run-build_microk8ssh"},"Run build_microk8s.sh"),(0,l.kt)("p",null,"When microk8s is running, run the following command from the root of the Ethereal Engine repo in WSL Ubuntu terminal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"export REGISTRY_HOST=microk8s.registry; export MYSQL_HOST=kubernetes.docker.internal;bash ./scripts/build_microk8s.sh\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,l.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your WSL terminal:")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,l.kt)("p",null,"The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on ",(0,l.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)"),(0,l.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached."),(0,l.kt)("p",null,"Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting ",(0,l.kt)("a",{parentName:"p",href:"http://microk8s.registry:32000/v2/_catalog"},"http://microk8s.registry:32000/v2/_catalog"),"."),(0,l.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,l.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"template")," for this file in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,l.kt)("p",null,"If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable ",(0,l.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to ",(0,l.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,l.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,l.kt)("p",null,'Before this step, ensure that all the agones and redis pods are in "Running" state. You can check pods status using the below command.'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl get pods\n")),(0,l.kt)("p",null,"Run the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("p",null,"After a minute or so, running ",(0,l.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting ",(0,l.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run ",(0,l.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),". The API pods will restart and will now not attempt to reinit the database on boot."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,l.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,l.kt)(o.ZP,{mdxType:"AcceptCertificates"}))}m.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>r});var a=n(7462),l=(n(7294),n(3905));const o={toc:[]},i="wrapper";function r(e){let{components:t,...n}=e;return(0,l.kt)(i,(0,a.Z)({},o,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,l.kt)("p",null,"Go to ",(0,l.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,l.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,l.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,l.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,l.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}r.isMDXComponent=!0},7233:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/docker-desktop-configuration-3bcd2b14180e1728b2d1c25965aab8a5.jpg"},5238:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/docker-desktop-wsl-distro-1e2000b68706625f1f44958b8c6fc623.jpg"},8488:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/wsl-ubuntu-default-1fc9022e83d8512beab359a72fc0502e.jpg"}}]); \ No newline at end of file diff --git a/es/assets/js/3ec03ade.f32e4786.js b/es/assets/js/3ec03ade.f32e4786.js new file mode 100644 index 000000000000..de661cccf389 --- /dev/null +++ b/es/assets/js/3ec03ade.f32e4786.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6916],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),h=o,f=p["".concat(l,".").concat(h)]||p[h]||d[h]||a;return n?r.createElement(f,i(i({ref:t},u),{},{components:n})):r.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var c=2;c<a;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},5545:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={},i="Running on Static IP under WSL2",s={unversionedId:"host/installation/running_on_static_IP",id:"host/installation/running_on_static_IP",title:"Running on Static IP under WSL2",description:"Follow these steps to run the engine on a static IP instead of localhost. In",source:"@site/docs/1_host/1_installation/5_running_on_static_IP.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/running_on_static_IP",permalink:"/etherealengine-docs/es/docs/host/installation/running_on_static_IP",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/5_running_on_static_IP.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Advanced Setup",permalink:"/etherealengine-docs/es/docs/host/installation/advanced_setup"},next:{title:"Troubleshooting",permalink:"/etherealengine-docs/es/docs/host/installation/install_troubleshooting"}},l={},c=[],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"running-on-static-ip-under-wsl2"},"Running on Static IP under WSL2"),(0,o.kt)("p",null,"Follow these steps to run the engine on a static IP instead of localhost. In\nmost cases you should be able to simply access the engine using the public IP\nassigned to your device, but if you run into any issues or if you are running\nthe stack on WSL2 then you can refer to the following directions."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Replace all localhost values with the static IP you want to run the stack on\nin your ",(0,o.kt)("inlineCode",{parentName:"li"},".env.local")," file."),(0,o.kt)("li",{parentName:"ol"},"Open a PowerShell terminal as admin. And run the ",(0,o.kt)("inlineCode",{parentName:"li"},"wsl2-port-forwarding.ps1"),"\nscript present under ",(0,o.kt)("inlineCode",{parentName:"li"},"/scripts")," directory.\nNote: Make sure all of the required ports are present in ports array of the\n",(0,o.kt)("inlineCode",{parentName:"li"},"wsl2-port-forwarding.ps1")," script."),(0,o.kt)("li",{parentName:"ol"},"And now just run the engine as you normally would and everything should be\naccessible over the static IP."),(0,o.kt)("li",{parentName:"ol"},"If you get any errors related to ",(0,o.kt)("strong",{parentName:"li"},"localhost:8642"),", then make sure that none of\nthe assets in your scene have been saved localhost path. If there are then\nreplace localhost with the static IP in the respective asset's path too.")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/46dcad74.58580c48.js b/es/assets/js/46dcad74.58580c48.js new file mode 100644 index 000000000000..1dffecfe4777 --- /dev/null +++ b/es/assets/js/46dcad74.58580c48.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5520],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>k});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 o(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 i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),c=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=c(e.components);return r.createElement(s.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=a,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return t?r.createElement(k,i(i({ref:n},p),{},{components:t})):r.createElement(k,i({ref:n},p))}));function k(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=t[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},6506:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=t(7462),a=(t(7294),t(3905));const o={},i="Troubleshooting",l={unversionedId:"host/installation/install_troubleshooting",id:"host/installation/install_troubleshooting",title:"Troubleshooting",description:"Browser Debug",source:"@site/docs/1_host/1_installation/6_install_troubleshooting.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/install_troubleshooting",permalink:"/etherealengine-docs/es/docs/host/installation/install_troubleshooting",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/6_install_troubleshooting.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Running on Static IP under WSL2",permalink:"/etherealengine-docs/es/docs/host/installation/running_on_static_IP"},next:{title:"Old Docker Instructions",permalink:"/etherealengine-docs/es/docs/host/installation/docker"}},s={},c=[{value:"Browser Debug",id:"browser-debug",level:3},{value:"Invalid Certificate errors in local environment",id:"invalid-certificate-errors-in-local-environment",level:3},{value:"Allow instanceserver address connection via installing local Certificate Authority",id:"allow-instanceserver-address-connection-via-installing-local-certificate-authority",level:3},{value:"Allow local file http-server connection with invalid certificate",id:"allow-local-file-http-server-connection-with-invalid-certificate",level:3},{value:"Allow instanceserver address connection with invalid certificate",id:"allow-instanceserver-address-connection-with-invalid-certificate",level:3},{value:"AccessDenied connecting to mariadb",id:"accessdenied-connecting-to-mariadb",level:3},{value:"Error: listen EADDRINUSE :::3030",id:"error-listen-eaddrinuse-3030",level:3},{value:"'CORS error' in terminal",id:"cors-error-in-terminal",level:3},{value:"Default blank screen",id:"default-blank-screen",level:3},{value:"Instanceserver or resource loading error?",id:"instanceserver-or-resource-loading-error",level:3},{value:"To install a new package for editor react components in monorepo",id:"to-install-a-new-package-for-editor-react-components-in-monorepo",level:3},{value:"Using Local Storage instead of MinIO",id:"using-local-storage-instead-of-minio",level:3},{value:"Accessing MinIO S3 storage provider running in local docker",id:"accessing-minio-s3-storage-provider-running-in-local-docker",level:3},{value:"Clear all data from MinIO S3 storage provider running in local docker",id:"clear-all-data-from-minio-s3-storage-provider-running-in-local-docker",level:3},{value:"DB not seeding routes (E.g. Error: No project installed- please contact site admin)",id:"db-not-seeding-routes-eg-error-no-project-installed--please-contact-site-admin",level:3},{value:"Weird issues with your database?",id:"weird-issues-with-your-database",level:3}],p={toc:c},d="wrapper";function u(e){let{components:n,...t}=e;return(0,a.kt)(d,(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"troubleshooting"},"Troubleshooting"),(0,a.kt)("h3",{id:"browser-debug"},"Browser Debug"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"p key")," debug colliders view"),(0,a.kt)("h3",{id:"invalid-certificate-errors-in-local-environment"},"Invalid Certificate errors in local environment"),(0,a.kt)("p",null,"As of this writing, the cert provided in the ethereal engine package for local use\nis not adequately signed. Browsers will throw up warnings about going to insecure pages.\nYou should be able to tell the browser to ignore it, usually by clicking on some sort\nof 'advanced options' button or link and then something along the lines of 'go there anyway'."),(0,a.kt)("p",null,"Chrome sometimes does not show a clickable option on the warning. If so, just\ntype ",(0,a.kt)("inlineCode",{parentName:"p"},"badidea")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"thisisunsafe")," when on that page. You don't enter that into the\naddress bar or into a text box, Chrome is just passively listening for those commands."),(0,a.kt)("h3",{id:"allow-instanceserver-address-connection-via-installing-local-certificate-authority"},"Allow instanceserver address connection via installing local Certificate Authority"),(0,a.kt)("p",null,"For more detailed instructions check: ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/FiloSottile/mkcert"},"https://github.com/FiloSottile/mkcert")),(0,a.kt)("p",null,"Short version (common for development process on Ubuntu):"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"sudo apt install libnss3-tools")),(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"brew install mkcert")," (if you don't have brew, check it's page: ",(0,a.kt)("a",{parentName:"li",href:"https://brew.sh/"},"https://brew.sh/"),")"),(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"mkcert --install")),(0,a.kt)("li",{parentName:"ol"},"Navigate to ",(0,a.kt)("inlineCode",{parentName:"li"},"./certs")," folder"),(0,a.kt)("li",{parentName:"ol"},"Execute ",(0,a.kt)("inlineCode",{parentName:"li"},"mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1"))),(0,a.kt)("h3",{id:"allow-local-file-http-server-connection-with-invalid-certificate"},"Allow local file http-server connection with invalid certificate"),(0,a.kt)("p",null,"Open the developer tools in your browser by pressing ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Shift+i")," at the\nsame time. Go to the 'Console' tab and look at the message history. If there are\nred errors that say something like\n",(0,a.kt)("inlineCode",{parentName:"p"},"GET https://127.0.0.1:3030/socket.io/?EIO=3&transport=polling&t=NXlZLTa net::ERR_CERT_AUTHORITY_INVALID"),",\nthen right-click that URL, then select 'Open in new tab', and accept the invalid certificate."),(0,a.kt)("h3",{id:"allow-instanceserver-address-connection-with-invalid-certificate"},"Allow instanceserver address connection with invalid certificate"),(0,a.kt)("p",null,"The instanceserver functionality is hosted on an address other than 127.0.0.1 in the local\nenvironment. Accepting an invalid certificate for 127.0.0.1 will not apply to this address.\nOpen the dev console for Chrome/Firefox by pressing ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Shift+i")," simultaneously, and\ngo to the Console or Network tabs."),(0,a.kt)("p",null,"If you see errors about not being able to connect to\nsomething like ",(0,a.kt)("inlineCode",{parentName:"p"},"https://192.168.0.81:3031/socket.io/?location=<foobar>"),", right click on\nthat URL and open it in a new tab. You should again get a warning page about an invalid\ncertificate, and you again need to allow it. "),(0,a.kt)("h3",{id:"accessdenied-connecting-to-mariadb"},"AccessDenied connecting to mariadb"),(0,a.kt)("p",null,"Make sure you don't have another instance of mariadb running on port 3306"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"lsof -i :3306\n")),(0,a.kt)("p",null,"On Linux, you can also check if any processes are running on port 3306 with\n",(0,a.kt)("inlineCode",{parentName:"p"},"sudo netstat -utlp | grep 3306"),"\nThe last column should look like ",(0,a.kt)("inlineCode",{parentName:"p"},"<ID>/<something"),"\nYou can kill any running process with ",(0,a.kt)("inlineCode",{parentName:"p"},"sudo kill <ID>")),(0,a.kt)("h3",{id:"error-listen-eaddrinuse-3030"},"Error: listen EADDRINUSE :::3030"),(0,a.kt)("p",null,"Check which process is using port 3030 and kill"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"killall -9 node \n")),(0,a.kt)("p",null,"Or"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"lsof -i :3030\nkill -3 <proccessIDfromPreviousCommand>\n")),(0,a.kt)("h3",{id:"cors-error-in-terminal"},"'CORS error' in terminal"),(0,a.kt)("p",null,"Try accessing the page using ",(0,a.kt)("inlineCode",{parentName:"p"},"https://localhost:3000"),"\ninstead of ",(0,a.kt)("inlineCode",{parentName:"p"},"https://127.0.0.1:3000")),(0,a.kt)("h3",{id:"default-blank-screen"},"Default blank screen"),(0,a.kt)("p",null,"Try typing ",(0,a.kt)("inlineCode",{parentName:"p"},"\u201cthisisunsafe\u201d")," or ",(0,a.kt)("inlineCode",{parentName:"p"},'"iknowwhatiamdoing"')," then reload page"),(0,a.kt)("h3",{id:"instanceserver-or-resource-loading-error"},"Instanceserver or resource loading error?"),(0,a.kt)("p",null,"Open dev console, click on the GET link in new tab and accept certificate by\ntyping ",(0,a.kt)("inlineCode",{parentName:"p"},"thisisunsafe\u201d")," or ",(0,a.kt)("inlineCode",{parentName:"p"},'"iknowwhatiamdoing"')," then reload original page"),(0,a.kt)("h3",{id:"to-install-a-new-package-for-editor-react-components-in-monorepo"},"To install a new package for editor react components in monorepo"),(0,a.kt)("p",null,"Type in terminal"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," npm i <packagename> -w @etherealengine/editor\n")),(0,a.kt)("h3",{id:"using-local-storage-instead-of-minio"},"Using Local Storage instead of MinIO"),(0,a.kt)("p",null,"Currently MinIO is used as default storage for local development. If you want to use local storage then do following steps:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"set ",(0,a.kt)("inlineCode",{parentName:"li"},"VITE_FILE_SERVER")," to the commented values under ",(0,a.kt)("inlineCode",{parentName:"li"},"# Use following value for local file server")," and comment out the values above it."),(0,a.kt)("li",{parentName:"ul"},"set ",(0,a.kt)("inlineCode",{parentName:"li"},"STORAGE_PROVIDER")," to ",(0,a.kt)("inlineCode",{parentName:"li"},"local"))),(0,a.kt)("h3",{id:"accessing-minio-s3-storage-provider-running-in-local-docker"},"Accessing MinIO S3 storage provider running in local docker"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Using ",(0,a.kt)("a",{parentName:"strong",href:"https://min.io/docs/minio/linux/administration/minio-console.html"},"MinIO Console"),":")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"When MinIO contain is running in your docker, navigate to ",(0,a.kt)("a",{parentName:"p",href:"https://localhost:9001/"},"https://localhost:9001/")," in your browser."),(0,a.kt)("blockquote",{parentName:"li"},(0,a.kt)("p",{parentName:"blockquote"},"Make sure to accept invalid certificate warning."))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},"Login using username as ",(0,a.kt)("inlineCode",{parentName:"p"},"server")," and password as ",(0,a.kt)("inlineCode",{parentName:"p"},"password"),"."),(0,a.kt)("blockquote",{parentName:"li"},(0,a.kt)("p",{parentName:"blockquote"},"You can find these credentials in ",(0,a.kt)("inlineCode",{parentName:"p"},"scripts/docker-compose.yml")," as ",(0,a.kt)("inlineCode",{parentName:"p"},"MINIO_ROOT_USER")," & ",(0,a.kt)("inlineCode",{parentName:"p"},"MINIO_ROOT_PASSWORD"))))),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Using ",(0,a.kt)("a",{parentName:"strong",href:"https://s3browser.com/"},"S3 Browser")," (Windows Only):")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Download & install S3 Browser from ",(0,a.kt)("a",{parentName:"li",href:"https://s3browser.com/download.aspx"},"https://s3browser.com/download.aspx"),"."),(0,a.kt)("li",{parentName:"ul"},"Launch and connect using following details:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Account Type: ",(0,a.kt)("strong",{parentName:"li"},"S3 Compatible Storage")),(0,a.kt)("li",{parentName:"ul"},"REST Endpoint: ",(0,a.kt)("strong",{parentName:"li"},"127.0.0.1:9000")),(0,a.kt)("li",{parentName:"ul"},"Access Key ID: ",(0,a.kt)("strong",{parentName:"li"},"server")),(0,a.kt)("li",{parentName:"ul"},"Secret Access Key: ",(0,a.kt)("strong",{parentName:"li"},"password")),(0,a.kt)("li",{parentName:"ul"},"Use secure transfer (SSL/TLS): ",(0,a.kt)("strong",{parentName:"li"},"Check / On / True"))))),(0,a.kt)("h3",{id:"clear-all-data-from-minio-s3-storage-provider-running-in-local-docker"},"Clear all data from MinIO S3 storage provider running in local docker"),(0,a.kt)("p",null,"Run following commands in your terminal:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," docker container stop etherealengine_minio_s3\n docker container rm etherealengine_minio_s3\n docker container prune --force\n docker volume prune --force\n npm run dev-docker\n npm run dev-reinit\n")),(0,a.kt)("h3",{id:"db-not-seeding-routes-eg-error-no-project-installed--please-contact-site-admin"},"DB not seeding routes (E.g. Error: No project installed- please contact site admin)"),(0,a.kt)("p",null,"Try"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," npm run dev-reinit \n")),(0,a.kt)("p",null,"or"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"}," docker container stop etherealengine_db\n docker container rm etherealengine_db\n docker container prune --force\n npm run dev-docker\n npm run dev-reinit\n")),(0,a.kt)("h3",{id:"weird-issues-with-your-database"},"Weird issues with your database?"),(0,a.kt)("p",null,"Try"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev-reinit\n")),(0,a.kt)("p",null,"Or if on windows"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"npm run dev-reinit-windows\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/47408852.8b910eaa.js b/es/assets/js/47408852.8b910eaa.js new file mode 100644 index 000000000000..b983b576701a --- /dev/null +++ b/es/assets/js/47408852.8b910eaa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2130],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function s(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function o(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?s(Object(n),!0).forEach((function(e){r(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function i(t,e){if(null==t)return{};var n,a,r=function(t,e){if(null==t)return{};var n,a,r={},s=Object.keys(t);for(a=0;a<s.length;a++)n=s[a],e.indexOf(n)>=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);for(a=0;a<s.length;a++)n=s[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var l=a.createContext({}),d=function(t){var e=a.useContext(l),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},p=function(t){var e=d(t.components);return a.createElement(l.Provider,{value:e},t.children)},u="mdxType",g={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},c=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,s=t.originalType,l=t.parentName,p=i(t,["components","mdxType","originalType","parentName"]),u=d(n),c=r,m=u["".concat(l,".").concat(c)]||u[c]||g[c]||s;return n?a.createElement(m,o(o({ref:e},p),{},{components:n})):a.createElement(m,o({ref:e},p))}));function m(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var s=n.length,o=new Array(s);o[0]=c;var i={};for(var l in e)hasOwnProperty.call(e,l)&&(i[l]=e[l]);i.originalType=t,i[u]="string"==typeof t?t:r,o[1]=i;for(var d=2;d<s;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},496:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>o,default:()=>g,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(7462),r=(n(7294),n(3905));const s={},o="Testing",i={unversionedId:"creator/testing/readme",id:"creator/testing/readme",title:"Testing",description:"Automated testing is a cornerstone to successful software development. Tests are",source:"@site/docs/2_creator/6_testing/readme.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/",permalink:"/etherealengine-docs/es/docs/creator/testing/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Unreal Bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge"},next:{title:"Testing Basics",permalink:"/etherealengine-docs/es/docs/creator/testing/testing_intro"}},l={},d=[{value:"SMTP Testing",id:"smtp-testing",level:2},{value:"Unit tests",id:"unit-tests",level:2},{value:"Integration tests",id:"integration-tests",level:2},{value:"Unit vs Integration Tests (source)",id:"unit-vs-integration-tests-source",level:2},{value:"System tests",id:"system-tests",level:2},{value:"End-to-end tests",id:"end-to-end-tests",level:2},{value:"System vs End-to-end Tests (source)",id:"system-vs-end-to-end-tests-source",level:2},{value:"White-box vs Black-box testing",id:"white-box-vs-black-box-testing",level:2},{value:"The Testing Pyramid",id:"the-testing-pyramid",level:2}],p={toc:d},u="wrapper";function g(t){let{components:e,...n}=t;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"testing"},"Testing"),(0,r.kt)("p",null,"Automated testing is a cornerstone to successful software development. Tests are\nnot just to ensure that your application is working as intended, they are also\nto ensure that ",(0,r.kt)("strong",{parentName:"p"},"existing features aren't broken by any newly introduced features\nor code"),", aka ",(0,r.kt)("strong",{parentName:"p"},"regression bugs"),". The latter tends to hold more value, as it\nmakes the software sturdy and less prone to these types of bugs during active\ndevelopment of a project. Regression bugs will quickly stall the development of\na project at a certain level of complexity, effectively preventing progress."),(0,r.kt)("h2",{id:"smtp-testing"},"SMTP Testing"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://mailtrap.io/inboxes"},"https://mailtrap.io/inboxes")),(0,r.kt)("p",null,"Add credentials in ",(0,r.kt)("inlineCode",{parentName:"p"},".env.local")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-dotenv"},"SMTP_HOST=smtp.mailtrap.io\nSMTP_PORT=2525\nSMTP_USER=<mailtrap-user>\nSMTP_PASS=<mailtrap-password>\n")),(0,r.kt)("h2",{id:"unit-tests"},"Unit tests"),(0,r.kt)("p",null,"Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const add2 = x => x + 2\n\nit('should add 2 to a given number', () => {\n strictEqual(add2(1), 3)\n})\n")),(0,r.kt)("h2",{id:"integration-tests"},"Integration tests"),(0,r.kt)("p",null,"Integration tests focus on testing bundles of code units. A composition of functions, for example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const addTwo = x => x + 2\nconst multThree = x => x * 3\nconst halve = x => x / 2\n\nconst algorithm = x => {\n x = addTwo(x)\n x = multThree(x)\n x = halve(x)\n return x\n}\n\nit('should apply the entire algorithm correctly', () => {\n strictEqual(algorithm(4), 9)\n})\n")),(0,r.kt)("h2",{id:"unit-vs-integration-tests-source"},"Unit vs Integration Tests (",(0,r.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-unit-testing-and-integration-testing/"},"source"),")"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Unit Testing"),(0,r.kt)("th",{parentName:"tr",align:null},"Integration Testing"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"In unit testing each module of the software is tested separately."),(0,r.kt)("td",{parentName:"tr",align:null},"In integration testing all modules of the the software are tested combined.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"In unit testing the tester knows the internal design of the software."),(0,r.kt)("td",{parentName:"tr",align:null},"In integration testing the tester doesn't know the internal design of the software.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is performed first of all testing processes."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is performed after unit testing, and before system/end-to-end tests.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is a white box testing."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is a black box testing.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is performed by the developer."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is performed by the tester.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Detection of defects in unit testing is easy."),(0,r.kt)("td",{parentName:"tr",align:null},"Detection of defects in integration testing is difficult.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It tests parts of the project without waiting for others to be completed."),(0,r.kt)("td",{parentName:"tr",align:null},"It tests only after the completion of all parts.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Unit testing is less costly."),(0,r.kt)("td",{parentName:"tr",align:null},"Integration testing is more costly.")))),(0,r.kt)("h2",{id:"system-tests"},"System tests"),(0,r.kt)("p",null,"System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test)."),(0,r.kt)("h2",{id:"end-to-end-tests"},"End-to-end tests"),(0,r.kt)("p",null,"End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow)."),(0,r.kt)("h2",{id:"system-vs-end-to-end-tests-source"},"System vs End-to-end Tests (",(0,r.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-system-testing-and-end-to-end-testing/"},"source"),")"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"System Testing"),(0,r.kt)("th",{parentName:"tr",align:null},"End-to-end Testing"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"In system testing, whole software or application is tested at a time."),(0,r.kt)("td",{parentName:"tr",align:null},"In end-to-end testing, behavioral flow of the software is tested.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"System testing only tests the specific software system."),(0,r.kt)("td",{parentName:"tr",align:null},"It tests the software system and the connected systems both.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"The functionality of the software is tested."),(0,r.kt)("td",{parentName:"tr",align:null},"Flow from end-to-end is tested.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It validates the software system as per standards and specifications."),(0,r.kt)("td",{parentName:"tr",align:null},"It validated all the interfaces of the software.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Knowledge of interconnected systems is not required."),(0,r.kt)("td",{parentName:"tr",align:null},"Knowledge about interconnected systems is required.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It is carried out once integration testing is performed."),(0,r.kt)("td",{parentName:"tr",align:null},"It is performed after the system testing.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It is performed both manually and automated."),(0,r.kt)("td",{parentName:"tr",align:null},"It is generally performed manually.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"It is the super set of end-to-end testing."),(0,r.kt)("td",{parentName:"tr",align:null},"It is considered as subset of the system testing.")))),(0,r.kt)("h2",{id:"white-box-vs-black-box-testing"},"White-box vs Black-box testing"),(0,r.kt)("p",null,"Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing."),(0,r.kt)("p",null,"Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing."),(0,r.kt)("h2",{id:"the-testing-pyramid"},"The Testing Pyramid"),(0,r.kt)("p",null,"A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution."),(0,r.kt)("p",null,"70% Unit tests"),(0,r.kt)("p",null,"20% Integration tests"),(0,r.kt)("p",null,"10% End-to-end tests"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"}," /```\\\n / E2E \\\n /_______\\\n / \\\n /Integration\\\n /_____________\\\n / \\\n / Unit \\\n/___________________\\\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/4972.512e2090.js b/es/assets/js/4972.512e2090.js new file mode 100644 index 000000000000..2aba19d26b5b --- /dev/null +++ b/es/assets/js/4972.512e2090.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4972],{4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>i});var a=n(7294),l=n(5999),o=n(833),r=n(7452);function i(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"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/es/assets/js/4a109b8c.295ebd36.js b/es/assets/js/4a109b8c.295ebd36.js new file mode 100644 index 000000000000..7d16f8f07eb3 --- /dev/null +++ b/es/assets/js/4a109b8c.295ebd36.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[943],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.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,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var p=2;p<o;p++)i[p]=n[p];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8960:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const o={},i="Projects",l={unversionedId:"creator/development/projects_overview",id:"creator/development/projects_overview",title:"Projects",description:"Projects are folders that contain all your custom code, assets and scenes. They",source:"@site/docs/2_creator/4_development/0_projects_overview.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/projects_overview",permalink:"/etherealengine-docs/es/docs/creator/development/projects_overview",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/0_projects_overview.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Development",permalink:"/etherealengine-docs/es/docs/creator/development/"},next:{title:"State Management",permalink:"/etherealengine-docs/es/docs/creator/development/state_management"}},s={},p=[{value:"File Structure",id:"file-structure",level:2},{value:"Config",id:"config",level:2},{value:"Hooks",id:"hooks",level:3},{value:"Thumbnail",id:"thumbnail",level:3},{value:"Routes",id:"routes",level:3},{value:"Webapp Injection",id:"webapp-injection",level:3},{value:"World Injection",id:"world-injection",level:3},{value:"Services",id:"services",level:3},{value:"Database Seeding",id:"database-seeding",level:3},{value:"i18n",id:"i18n",level:3}],c={toc:p},d="wrapper";function u(e){let{components:t,...o}=e;return(0,r.kt)(d,(0,a.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"projects"},"Projects"),(0,r.kt)("p",null,"Projects are folders that contain all your custom code, assets and scenes. They\nare version controlled using git & github, and can be installed to any deployment\nwith a single click. (more on that in the ",(0,r.kt)("a",{parentName:"p",href:"./3_editor_scenes_locations.md"},"next chapter"),")"),(0,r.kt)("p",null,"Pictured below is an example of 4 projects installed. By default, only the\n",(0,r.kt)("inlineCode",{parentName:"p"},"default-project")," is installed, which in a production environment is read only.\nYou can find the default project under ",(0,r.kt)("inlineCode",{parentName:"p"},"/packages/projects/default-project/")),(0,r.kt)("p",null,"In a production environment, the builder process will install all projects\naccording to the ",(0,r.kt)("inlineCode",{parentName:"p"},"project")," database table and will download files from the\nstorage provider. In a local development environment, the local file system is\nalways the source of truth. Any project folders added or removed from the file\nsystem will be automatically added or removed from the database. This is to\nensure there is no accidental loss of data, as these project folders are all git\nrepositories."),(0,r.kt)("p",null,(0,r.kt)("img",{src:n(8098).Z,width:"263",height:"241"})),(0,r.kt)("h2",{id:"file-structure"},"File Structure"),(0,r.kt)("p",null,"Projects have a few conventions."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"assets/")," is where files uploaded from the editor will be uploaded to")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"src/")," is where code assets can be served from")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"tests/")," is where test files can be run")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"sceneName.scene.json")," is a scene file")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"sceneName.thumbnail.png")," is an auto-generated scene thumbnail file")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"xrengine.config.ts")," the project configuration, where client routes, database\nmodels, feathers services and the project thumbnail can be defined"))),(0,r.kt)("p",null,"A project must also have a package.json to provide custom dependencies, and to define\nthe project name, project version, and Ethereal Engine version it is known to work with."),(0,r.kt)("p",null,"Systems imported from a scene MUST have their filename end with ",(0,r.kt)("inlineCode",{parentName:"p"},"System.ts")," and be in the ",(0,r.kt)("inlineCode",{parentName:"p"},"/src/systems")," folder.\nThis is to optimize vite's code-splitting bundling process, as each potentially dynamically\nimportable file will result in a new bundle with it's own copy of all of it's import dependencies."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"@etherealengine/*")," monorepo dependencies will be symlinked and not needed, but some\npackage managers (such as pnpm) require these to be defined. If so, they should\nbe defined in ",(0,r.kt)("inlineCode",{parentName:"p"},"peerDependencies")," and kept up to date with the current engine version."),(0,r.kt)("h2",{id:"config"},"Config"),(0,r.kt)("p",null,"The ethereal engine config file has the following options:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"export interface ProjectConfigInterface {\n onEvent?: string\n thumbnail?: string\n routes?: {\n [route: string]: {\n component: () => Promise<{ default: (props: any) => JSX.Element }>\n props?: {\n [x: string]: any\n exact?: boolean\n }\n }\n }\n webappInjection?: () => Promise<{ default: (props: any) => void | JSX.Element }>\n worldInjection?: () => Promise<{ default: () => Promise<void> }>\n services?: string\n databaseSeed?: string\n settings?: Array<ProjectSettingSchema>\n}\n")),(0,r.kt)("h3",{id:"hooks"},"Hooks"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"onEvent")," property is a relative path string that points to a file which\nmust expose an object with properties as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"export interface ProjectEventHooks {\n onInstall?: (app: Application) => Promise<any>\n onLoad?: (app: Application) => Promise<any>\n onUpdate?: (app: Application) => Promise<any>\n onUninstall?: (app: Application) => Promise<any>\n /**\n * get oEmbed for active routes that match URL\n * return that project's onOEmbedRequest()\n * if null, return default\n */\n onOEmbedRequest?: (app: Application, url: URL, currentOEmbed: OEmbed) => Promise<OEmbed | null>\n}\n")),(0,r.kt)("p",null,"These functions are called when the project they belong to are installed,\nupdated (such as scenes saved) or uninstalled respectively. This is used in the\ndefault ethereal engine project to install the default avatars.\nSee ",(0,r.kt)("inlineCode",{parentName:"p"},"/packages/projects/default-project/projectEventHooks.ts"),"."),(0,r.kt)("h3",{id:"thumbnail"},"Thumbnail"),(0,r.kt)("p",null,"This is a URL to a thumbnail for the project."),(0,r.kt)("h3",{id:"routes"},"Routes"),(0,r.kt)("p",null,"Routes enable users to customise the various URL paths of their website\nutilising dynamic loading of modules. The key of each object represents the path\n(with leading forward slash included) while the value represents a react\ncomponent object which gets wrapped in ",(0,r.kt)("inlineCode",{parentName:"p"},"React.lazy()")," and a props object which\npasses options into the react-dom-router Route component corresponding to the route."),(0,r.kt)("h3",{id:"webapp-injection"},"Webapp Injection"),(0,r.kt)("p",null,"Webapp injection allows logic to be run on all pages, loaded before any routes\nare loaded. This will soon be extended to allow easy stylesheet injection and\nother configurables of the webapp."),(0,r.kt)("h3",{id:"world-injection"},"World Injection"),(0,r.kt)("p",null,"World injection allows logic to be run every time a new world is created,\ncurrently only when the engine is initialised. This is loaded on all instances\nof the engine, such as a location and the editor. An example use case of this\nwould be registering custom scene loader and editor prefabs."),(0,r.kt)("h3",{id:"services"},"Services"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"services")," property is a relative path that points to a file which must\nreturn type ",(0,r.kt)("inlineCode",{parentName:"p"},"((app: Application) => Promise<any>)[]")," which is run on all\ninstanceservers and api servers at startup. This allows users to expose custom\nFeathers services, or whatever other functionality they made need."),(0,r.kt)("h3",{id:"database-seeding"},"Database Seeding"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"databaseSeed")," property is a relative path that points to a file which must\nreturn type ",(0,r.kt)("inlineCode",{parentName:"p"},"ServicesSeedConfig")," from ",(0,r.kt)("inlineCode",{parentName:"p"},"../packages/common/src/interfaces/ServicesSeedConfig.ts"),"\nwhich is run when the database seeder is run."),(0,r.kt)("h3",{id:"i18n"},"i18n"),(0,r.kt)("p",null,"Internationalization can be added using the pattern ",(0,r.kt)("inlineCode",{parentName:"p"},"./i18n/<language>/<namespace>.json"),". An example of the format can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/tree/dev/packages/client-core/i18n"},"the base i18n files"),"."))}u.isMDXComponent=!0},8098:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/projects-folder-b0a16be5a64322e12f81233c0a19f898.png"}}]); \ No newline at end of file diff --git a/es/assets/js/4a62c6ed.658385a6.js b/es/assets/js/4a62c6ed.658385a6.js new file mode 100644 index 000000000000..da0f4be56dae --- /dev/null +++ b/es/assets/js/4a62c6ed.658385a6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5624],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 c(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,c(c({ref:t},s),{},{components:r})):n.createElement(f,c({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var p=2;p<a;p++)c[p]=r[p];return n.createElement.apply(null,c)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},8510:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={},c="Development",i={unversionedId:"creator/development/readme",id:"creator/development/readme",title:"Development",description:"In this section you will find out how to create your own projects with Ethereal Engine.",source:"@site/docs/2_creator/4_development/readme.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/",permalink:"/etherealengine-docs/es/docs/creator/development/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Asset Import Pipeline",permalink:"/etherealengine-docs/es/docs/creator/importing_assets/"},next:{title:"Projects",permalink:"/etherealengine-docs/es/docs/creator/development/projects_overview"}},l={},p=[],s={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"development"},"Development"),(0,o.kt)("p",null,"In this section you will find out how to create your own projects with Ethereal Engine."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/4b422948.6f450d33.js b/es/assets/js/4b422948.6f450d33.js new file mode 100644 index 000000000000..91bb3c914d53 --- /dev/null +++ b/es/assets/js/4b422948.6f450d33.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3881],{3905:(e,A,t)=>{t.d(A,{Zo:()=>p,kt:()=>h});var a=t(7294);function n(e,A,t){return A in e?Object.defineProperty(e,A,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[A]=t,e}function o(e,A){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);A&&(a=a.filter((function(A){return Object.getOwnPropertyDescriptor(e,A).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var A=1;A<arguments.length;A++){var t=null!=arguments[A]?arguments[A]:{};A%2?o(Object(t),!0).forEach((function(A){n(e,A,t[A])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(A){Object.defineProperty(e,A,Object.getOwnPropertyDescriptor(t,A))}))}return e}function l(e,A){if(null==e)return{};var t,a,n=function(e,A){if(null==e)return{};var t,a,n={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],A.indexOf(t)>=0||(n[t]=e[t]);return n}(e,A);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],A.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var r=a.createContext({}),s=function(e){var A=a.useContext(r),t=A;return e&&(t="function"==typeof e?e(A):i(i({},A),e)),t},p=function(e){var A=s(e.components);return a.createElement(r.Provider,{value:A},e.children)},w="mdxType",c={inlineCode:"code",wrapper:function(e){var A=e.children;return a.createElement(a.Fragment,{},A)}},u=a.forwardRef((function(e,A){var t=e.components,n=e.mdxType,o=e.originalType,r=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),w=s(t),u=n,h=w["".concat(r,".").concat(u)]||w[u]||c[u]||o;return t?a.createElement(h,i(i({ref:A},p),{},{components:t})):a.createElement(h,i({ref:A},p))}));function h(e,A){var t=arguments,n=A&&A.mdxType;if("string"==typeof e||n){var o=t.length,i=new Array(o);i[0]=u;var l={};for(var r in A)hasOwnProperty.call(A,r)&&(l[r]=A[r]);l.originalType=e,l[w]="string"==typeof e?e:n,i[1]=l;for(var s=2;s<o;s++)i[s]=t[s];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}u.displayName="MDXCreateElement"},3825:(e,A,t)=>{t.r(A),t.d(A,{assets:()=>m,contentTitle:()=>D,default:()=>b,frontMatter:()=>k,metadata:()=>f,toc:()=>E});var a=t(7462),n=(t(7294),t(3905));const o={toc:[]},i="wrapper";function l(e){let{components:A,...t}=e;return(0,n.kt)(i,(0,a.Z)({},o,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this step, you need to provide sudo password for linux terminal. This is because Control Center App will perform various actions on your system with admin privileges."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Windows, this is the password of your WSL Ubuntu distribution's sudo user.")))}l.isMDXComponent=!0;const r={toc:[]},s="wrapper";function p(e){let{components:A,...t}=e;return(0,n.kt)(s,(0,a.Z)({},r,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this step, you will need to provide following information:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Engine Path:")," This is the location of ethereal engine source code repo. If the path does not contain the source code, then it will be ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine"},"cloned")," by Control Center App."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"On Windows, the path must be inside WSL Ubuntu distribution."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Ops Path:")," This is the location of ethereal engine ops source code repo. If the path does not contain the source code, then it will be ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"cloned")," by Control Center App."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"On Windows, the path must be inside WSL Ubuntu distribution."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Enable Ripple Stack:")," By default you should keep this option as off unless you want to have IPFS & rippled server running in your local K8s deployment.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Force DB Refresh:")," This will truncate database tables & repopulate them with seed data."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"If the database is empty, then Control Center App will itself force populate it.")))))}p.isMDXComponent=!0;const w={toc:[]},c="wrapper";function u(e){let{components:A,...t}=e;return(0,n.kt)(c,(0,a.Z)({},w,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"In this step for most of the users, go with the default variable values and leave the text fields as it is."),(0,n.kt)("p",null,"For advanced setup, if you want to configure oAuth, S3 file storage, email, SMS support then you can provide variable values."))}u.isMDXComponent=!0;const h={toc:[]},g="wrapper";function d(e){let{components:A,...t}=e;return(0,n.kt)(g,(0,a.Z)({},h,t,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"This step will show a summary of all the previous steps. User can review them before proceeding ahead."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Please make sure to read ",(0,n.kt)("inlineCode",{parentName:"p"},"Note")," on this screen.")),(0,n.kt)("p",null,"Afterwards, there are following option(s):"))}d.isMDXComponent=!0;const k={hide_table_of_contents:!0},D="Getting Started",f={unversionedId:"host/devops_deployment/tutorials/ethereal_control_center/getting_started",id:"host/devops_deployment/tutorials/ethereal_control_center/getting_started",title:"Getting Started",description:"The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster.",source:"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/01_getting_started.md",sourceDirName:"1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center",slug:"/host/devops_deployment/tutorials/ethereal_control_center/getting_started",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/01_getting_started.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Control Center App",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/"},next:{title:"Ethereal Engine Admin Panel Guide",permalink:"/etherealengine-docs/es/docs/host/Admin_Dashboard/"}},m={},E=[{value:"App Overview",id:"app-overview",level:2},{value:"1. Downloading Control Center App",id:"1-downloading-control-center-app",level:2},{value:"2. Launch & Create Cluster",id:"2-launch--create-cluster",level:2},{value:"2.1. Cluster Information",id:"21-cluster-information",level:3},{value:"2.2. Cluster Type: MicroK8s or Minikube",id:"22-cluster-type-microk8s-or-minikube",level:3},{value:"2.2.1. Authentication",id:"221-authentication",level:3},{value:"2.2.2. Configurations",id:"222-configurations",level:3},{value:"2.2.3. Variables",id:"223-variables",level:3},{value:"2.2.4. Summary",id:"224-summary",level:3},{value:"2.3. Cluster Type: Custom",id:"23-cluster-type-custom",level:3},{value:"2.3.1. Kubeconfig",id:"231-kubeconfig",level:3},{value:"2.3.2. Deployment",id:"232-deployment",level:3},{value:"2.3.3. Summary",id:"233-summary",level:3},{value:"3. Cluster Screen",id:"3-cluster-screen",level:2},{value:"3.1. Hotbar",id:"31-hotbar",level:3},{value:"3.2. Navbar",id:"32-navbar",level:3},{value:"3.3. Options Panel",id:"33-options-panel",level:3},{value:"3.4. System Status",id:"34-system-status",level:3},{value:"3.5. Apps Status",id:"35-apps-status",level:3},{value:"3.6. Engine Status",id:"36-engine-status",level:3},{value:"3.7. Logs",id:"37-logs",level:3},{value:"4. Configure Cluster",id:"4-configure-cluster",level:2},{value:"4.1. Authentication",id:"41-authentication",level:3},{value:"4.2. Configurations",id:"42-configurations",level:3},{value:"4.3. Variables",id:"43-variables",level:3},{value:"4.4. Summary",id:"44-summary",level:3},{value:"5. Launch Ethereal Engine",id:"5-launch-ethereal-engine",level:2},{value:"6. Workloads",id:"6-workloads",level:2},{value:"6.1. Workload Tabs",id:"61-workload-tabs",level:3},{value:"6.2. Workloads Table",id:"62-workloads-table",level:3},{value:"6.3. Workload Logs",id:"63-workload-logs",level:3},{value:"7. Admin Dashboard",id:"7-admin-dashboard",level:2},{value:"8. K8 Dashboard",id:"8-k8-dashboard",level:2},{value:"9. IPFS",id:"9-ipfs",level:2},{value:"10. Rippled CLI",id:"10-rippled-cli",level:2},{value:"11. Updating the App",id:"11-updating-the-app",level:2}],B={toc:E},M="wrapper";function b(e){let{components:A,...o}=e;return(0,n.kt)(M,(0,a.Z)({},B,o,{components:A,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"getting-started"},"Getting Started"),(0,n.kt)("p",null,"The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster."),(0,n.kt)("p",null,"We know it's been complicated to build with Ethereal Engine and we've made this tool to give the community easy access to the engine. We would love to see your creations and invite you all to come build with us."),(0,n.kt)("h2",{id:"app-overview"},"App Overview"),(0,n.kt)("p",null,"The Ethereal Engine Control Center app provides access to various functionalities which includes:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Configure your Ethereal Engine in a cluster in just a few clicks."),(0,n.kt)("li",{parentName:"ul"},"View status of Ethereal Engine dependencies on your local system."),(0,n.kt)("li",{parentName:"ul"},"Manage an Ethereal Engine deployment through admin panel."),(0,n.kt)("li",{parentName:"ul"},"Manage kubernetes cluster through its dashboard."),(0,n.kt)("li",{parentName:"ul"},"Manage IPFS node running in the cluster."),(0,n.kt)("li",{parentName:"ul"},"Execute commands against rippled server."),(0,n.kt)("li",{parentName:"ul"},"See realtime logs of different actions being performed.")),(0,n.kt)("h2",{id:"1-downloading-control-center-app"},"1. Downloading Control Center App"),(0,n.kt)("p",null,"In order to download Ethereal Engine Control Center App, navigate to ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine-control-center/releases"},"releases")," page and download the latest version of the App. On Windows (and for WSL), you will need to download ",(0,n.kt)("inlineCode",{parentName:"p"},".exe")," while for linux download ",(0,n.kt)("inlineCode",{parentName:"p"},"AppImage"),"."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Windows, you will need to allow permission for executing ps1 scripts. You can do so by running following command in Powershell with admin privileges (",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine-control-center#2-windows-permission-to-run-ps1-scripts"},"reference"),")."),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-Powershell"},"Set-ExecutionPolicy -ExecutionPolicy Unrestricted\n"))),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Linux, once downloaded, right click and go to ",(0,n.kt)("strong",{parentName:"p"},"Properties")," of AppImage. In ",(0,n.kt)("strong",{parentName:"p"},"Permissions")," tab check 'Allow executing file as program'. Afterwards, double click on AppImage to launch the app.")),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"On Ubuntu 22.04 or later, if you are unable to launch AppImage then you might have to install Fuse using following command in terminal (",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/etherealengine-control-center#1-app-not-launching-in-ubuntu-2204"},"reference"),")."),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get install fuse libfuse2\n"))),(0,n.kt)("h2",{id:"2-launch--create-cluster"},"2. Launch & Create Cluster"),(0,n.kt)("p",null,"When you launch the app for the first time, you will see below screen:"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Home Screen",src:t(8370).Z,width:"1919",height:"1001"})),(0,n.kt)("p",null,"Here you need to create a cluster. You can do so by clicking on ",(0,n.kt)("inlineCode",{parentName:"p"},"Create")," button in the center or anytime using round plus button on left bottom corner (in ",(0,n.kt)("a",{parentName:"p",href:"#31-hotbar"},"hotbar"),") of the screen. Following are the different sections of create cluster dialog:"),(0,n.kt)("h3",{id:"21-cluster-information"},"2.1. Cluster Information"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Cluster Information",src:t(453).Z,width:"596",height:"552"})),(0,n.kt)("p",null,"In this step, you will need to provide following information:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Name:")," This can be any name you want to give your cluster. i.e. Local, my-metaverse, etc.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Type:")," This will be the kubernetes distribution you want to use. Currently there are 2 local distributions, MicroK8s(recommended) & Minikube. There is also a Custom type which allows you to connect to an existing Ethereal Engine cluster."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Currently, ",(0,n.kt)("inlineCode",{parentName:"p"},"MicroK8s")," is supported on Windows & Linux while ",(0,n.kt)("inlineCode",{parentName:"p"},"Minikube")," is supported on Linux only."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Prerequisites:")," These are the set of items that should be manually configured by the user. If an item is correctly setup then its status will be green tick, else it will have a red cross with details and link to docs for the corrective measures."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Currently, there are prerequisites for MicroK8s in Windows only.")))),(0,n.kt)("h3",{id:"22-cluster-type-microk8s-or-minikube"},"2.2. Cluster Type: MicroK8s or Minikube"),(0,n.kt)("p",null,"If you selected cluster type as MicroK8s or Minikube, then you will see below options."),(0,n.kt)("h3",{id:"221-authentication"},"2.2.1. Authentication"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Authentication",src:t(2569).Z,width:"597",height:"580"})),(0,n.kt)(l,{mdxType:"StepAuthentication"}),(0,n.kt)("h3",{id:"222-configurations"},"2.2.2. Configurations"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Configurations",src:t(4910).Z,width:"597",height:"553"})),(0,n.kt)(p,{mdxType:"StepConfigurations"}),(0,n.kt)("h3",{id:"223-variables"},"2.2.3. Variables"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Variables",src:t(4890).Z,width:"599",height:"554"})),(0,n.kt)(u,{mdxType:"StepVariables"}),(0,n.kt)("h3",{id:"224-summary"},"2.2.4. Summary"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Summary",src:t(2343).Z,width:"594",height:"695"})),(0,n.kt)(d,{mdxType:"StepSummary"}),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Create:")," By default you should go with this option as it will create the cluster entry and show the ",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"cluster screen")," of this cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Create & Configure:")," This will create the cluster entry and show the current status of things. And afterwards it will automatically start the configuration script to ensure things are setup."))),(0,n.kt)("blockquote",null,(0,n.kt)("blockquote",{parentName:"blockquote"},(0,n.kt)("p",{parentName:"blockquote"},"If you use 'Create' option, then you can still run the Configure script as discussed later in this ",(0,n.kt)("a",{parentName:"p",href:"#4-configure-cluster"},"guide"),"."))),(0,n.kt)("h3",{id:"23-cluster-type-custom"},"2.3. Cluster Type: Custom"),(0,n.kt)("p",null,"If you selected Custom cluster type, then you will see below options. Custom cluster allows to connect to an existing kubernetes cluster."),(0,n.kt)("h3",{id:"231-kubeconfig"},"2.3.1. Kubeconfig"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Kubeconfig",src:t(9611).Z,width:"594",height:"546"})),(0,n.kt)("p",null,"In this step, you will need to provide following information regarding desired cluster's kubeconfig:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config Type - Default:")," This will load the default kubeconfig file of your system.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config Type - File:")," This will allow to load kubeconfig from a file of your system.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config Type - Text:")," This will allow to load kubeconfig from a text.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Context:")," This is the selected kube context of cluster in which your ethereal engine deployment exists. The dropdown will show all contexts that exist in selected config type."))),(0,n.kt)("h3",{id:"232-deployment"},"2.3.2. Deployment"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Deployment",src:t(9015).Z,width:"596",height:"547"})),(0,n.kt)("p",null,"In this step, you will need to provide following deployment information:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Release Name:")," This is the name of your release in selected kubernetes deployment. It can be 'dev', 'prod', 'local', etc.",(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Release name is used to prefix the workloads in your cluster like:\n",(0,n.kt)("inlineCode",{parentName:"p"},"{RELEASE_NAME}-etherealengine-client"),". i.e. ",(0,n.kt)("inlineCode",{parentName:"p"},"prod-etherealengine-client"))))),(0,n.kt)("h3",{id:"233-summary"},"2.3.3. Summary"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Create Cluster - Summary",src:t(5847).Z,width:"595",height:"545"})),(0,n.kt)(d,{mdxType:"StepSummary"}),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Create:")," This option will create the cluster entry and show the ",(0,n.kt)("a",{parentName:"li",href:"#6-workloads"},"workloads screen")," of this cluster.")),(0,n.kt)("h2",{id:"3-cluster-screen"},"3. Cluster Screen"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Cluster Screen",src:t(8682).Z,width:"1916",height:"1005"})),(0,n.kt)("p",null,"Once you have created a cluster you will be navigated to its screen also know as config page. Lets explain various sections of this screen:"),(0,n.kt)("h3",{id:"31-hotbar"},"3.1. Hotbar"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Hotbar",src:t(6290).Z,width:"97",height:"323"})),(0,n.kt)("p",null,"It will show you a list of all clusters you have created. You can click on each of them to view the cluster screen of them."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Add Cluster Icon",src:t(380).Z,width:"29",height:"29"})," The plus icon at the bottom of this bar is used to create a new cluster."),(0,n.kt)("h3",{id:"32-navbar"},"3.2. Navbar"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Navbar",src:t(1977).Z,width:"983",height:"70"})),(0,n.kt)("p",null,"This section allows navigation and various utility options. Following are the various options in it:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"App Icon:")," ",(0,n.kt)("img",{alt:"App Icon",src:t(8e3).Z,width:"152",height:"36"})," Logo of this application.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Home Icon:")," ",(0,n.kt)("img",{alt:"Home Icon",src:t(6072).Z,width:"46",height:"28"})," Navigate to home.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Config:")," Navigates to ",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"cluster")," screen of selected cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Workloads:")," Navigates to ",(0,n.kt)("a",{parentName:"p",href:"#6-workloads"},"workloads")," screen of selected cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Admin:")," Navigates to ethereal engine ",(0,n.kt)("a",{parentName:"p",href:"#7-admin-dashboard"},"admin")," panel of selected cluster.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"K8 Dashboard:")," Navigates to kubernetes ",(0,n.kt)("a",{parentName:"p",href:"#8-k8-dashboard"},"web dashboard")," of selected kubernetes distribution.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"IPFS:")," Navigates to IPFS ",(0,n.kt)("a",{parentName:"p",href:"#9-ipfs"},"web UI")," of selected cluster. This option is visible only if ripple stack is enabled.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Rippled CLI:")," Navigates to rippled ",(0,n.kt)("a",{parentName:"p",href:"#10-rippled-cli"},"server cli")," of selected cluster. This option is visible only if ripple stack is enabled.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Change Theme Icon:")," ",(0,n.kt)("img",{alt:"Change Theme Icon",src:t(2764).Z,width:"49",height:"30"})," Allows to toggle between vaporware, light & dark themes. The color scheme of these themes are similar to ethereal engine.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Support Icon:")," ",(0,n.kt)("img",{alt:"Support Icon",src:t(9026).Z,width:"46",height:"28"})," Opens a dropdown menu to allow reaching out to support via Discord or Github.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"User Icon:")," ",(0,n.kt)("img",{alt:"User Icon",src:t(6424).Z,width:"49",height:"29"})," The functionality for this button is coming soon."))),(0,n.kt)("h3",{id:"33-options-panel"},"3.3. Options Panel"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Options Panel",src:t(807).Z,width:"1212",height:"72"})),(0,n.kt)("p",null,"This section shows various actions against currently selected cluster. Following are the options in it:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Icon:")," ",(0,n.kt)("img",{alt:"Cluster Icon",src:t(8082).Z,width:"27",height:"26"})," Logo of the selected cluster type. It can be MicroK8s or Minikube logo.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Cluster Name:")," This is the cluster name that you entered in create cluster dialog. i.e. Local.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Engine Git Status:")," ",(0,n.kt)("img",{alt:"Cluster Icon",src:t(2383).Z,width:"133",height:"28"})," This is used to view current status of local ethereal engine github repo. You can view & change current branch, view & pull incoming changes, view & push outgoing changes.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Ops Git Status:")," ",(0,n.kt)("img",{alt:"Cluster Icon",src:t(4601).Z,width:"137",height:"28"})," This is used to view current status of local ethereal engine ops github repo. You can perform all actions as explained for engine git status.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Refresh Icon:")," ",(0,n.kt)("img",{alt:"Refresh Icon",src:t(9662).Z,width:"31",height:"26"})," This will recheck the status of prerequisites, system, apps & engine. It also, recheck the status of engine and ops git repos. If a refresh is already in process then it will be disabled until its finished.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Delete Icon:")," ",(0,n.kt)("img",{alt:"Delete Icon",src:t(5987).Z,width:"26",height:"26"})," This will delete a clusters. It would not make any changes in associated local kubernetes, app, etc.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Settings Icon:")," ",(0,n.kt)("img",{alt:"Settings Icon",src:t(7697).Z,width:"30",height:"26"})," This will open settings dialog. It contains some selected cluster specific settings in addition to general app settings.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Configure Button:")," ",(0,n.kt)("img",{alt:"Configure Button",src:t(5401).Z,width:"85",height:"36"})," This will open the configure dialog which is ",(0,n.kt)("a",{parentName:"p",href:"#4-configure-cluster"},"discussed")," later. If a configuration is already running then this button will be disabled and have a spinner in it.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Launch Button:")," ",(0,n.kt)("img",{alt:"Launch Button",src:t(3377).Z,width:"65",height:"36"})," This button will open Ethereal Engine's default location in your browser as ",(0,n.kt)("a",{parentName:"p",href:"#5-launch-ethereal-engine"},"discussed")," later."))),(0,n.kt)("h3",{id:"34-system-status"},"3.4. System Status"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"System Status",src:t(1412).Z,width:"1793",height:"133"})),(0,n.kt)("p",null,"This section will show the current status of whether the system requirements are meet or not. On Windows, it will also show the status of prerequisites."),(0,n.kt)("p",null,"The status against each item will be displayed. You can find more details by hovering over ",(0,n.kt)("img",{alt:"Info Icon",src:t(5048).Z,width:"25",height:"24"})," info icon. This info icon is useful when some item is not configured correctly."),(0,n.kt)("p",null,"Additionally, for some items you will see ",(0,n.kt)("img",{alt:"Fix Icon",src:t(5071).Z,width:"28",height:"29"})," auto fix icon. Clicking this button will try to auto fix the problem. Though if it fails, you can try using configure dialog which is ",(0,n.kt)("a",{parentName:"p",href:"#4-configure-cluster"},"discussed")," later."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Usually, auto fix button should only be used if previously you were able to run the cluster successfully. Otherwise, use configure dialog.")),(0,n.kt)("h3",{id:"35-apps-status"},"3.5. Apps Status"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Apps Status",src:t(790).Z,width:"1788",height:"255"})),(0,n.kt)("p",null,"This section will show the current status of all the apps required to run ethereal engine deployment."),(0,n.kt)("h3",{id:"36-engine-status"},"3.6. Engine Status"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Engine Status",src:t(7164).Z,width:"1791",height:"97"})),(0,n.kt)("p",null,"This section will show the current status of various components of ethereal engine deployment in your local kubernetes distribution."),(0,n.kt)("h3",{id:"37-logs"},"3.7. Logs"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Logs",src:t(8121).Z,width:"1792",height:"252"})),(0,n.kt)("p",null,"This section will show all the logs of current session. The logs are of the different actions being performed by control center and their output."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Download Button:")," ",(0,n.kt)("img",{alt:"Download Button",src:t(4783).Z,width:"28",height:"33"})," This will download all displayed logs.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Clear Button:")," ",(0,n.kt)("img",{alt:"Clear Button",src:t(2038).Z,width:"31",height:"33"})," This will clear all displayed logs."))),(0,n.kt)("h2",{id:"4-configure-cluster"},"4. Configure Cluster"),(0,n.kt)("p",null,"On (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"cluster screen"),"), if any of the status is not green tick then it means you need to run the configure script to fix them automatically. To do so use the Configure (",(0,n.kt)("img",{alt:"Configure Button",src:t(5401).Z,width:"85",height:"36"}),") button in the ",(0,n.kt)("a",{parentName:"p",href:"#33-options-panel"},"options panel"),". Following are the different sections of configure cluster dialog:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Its always recommended to clear your logs before running configure script in order to trace outputs easily.")),(0,n.kt)("h3",{id:"41-authentication"},"4.1. Authentication"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Authentication",src:t(9478).Z,width:"596",height:"576"})),(0,n.kt)(l,{mdxType:"StepAuthentication"}),(0,n.kt)("h3",{id:"42-configurations"},"4.2. Configurations"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Configurations",src:t(2725).Z,width:"594",height:"544"})),(0,n.kt)(p,{mdxType:"StepConfigurations"}),(0,n.kt)("h3",{id:"43-variables"},"4.3. Variables"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Variables",src:t(9757).Z,width:"594",height:"594"})),(0,n.kt)(u,{mdxType:"StepVariables"}),(0,n.kt)("h3",{id:"44-summary"},"4.4. Summary"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Configure Cluster - Summary",src:t(2718).Z,width:"600",height:"687"})),(0,n.kt)(d,{mdxType:"StepSummary"}),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Configure:")," This will start the configuration script which will ensure things are setup. You can track output of various things in ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs"),". Depending on your system and status of apps, it can take a while to setup things. As the configure script is executing, the Configure (",(0,n.kt)("img",{alt:"Configure Button",src:t(5401).Z,width:"85",height:"36"}),") button will be disabled and have a spinner in it."),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"Once the script finished its execution, the cluster status will be automatically refreshed.")),(0,n.kt)("blockquote",{parentName:"li"},(0,n.kt)("p",{parentName:"blockquote"},"If the configure script failed, pay close attention to last few lines of ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs")," section. As it will contain the reason why script failed.")))),(0,n.kt)("h2",{id:"5-launch-ethereal-engine"},"5. Launch Ethereal Engine"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Launch Ethereal Engine",src:t(4832).Z,width:"1919",height:"930"})),(0,n.kt)("p",null,"Once, everything is configured correctly and all ticks are green on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"Launch")," button in ",(0,n.kt)("a",{parentName:"p",href:"#33-options-panel"},"options panel"),". This button will open Ethereal Engine's default location in your browser."),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Make sure to allow certificates as explained ",(0,n.kt)("a",{parentName:"p",href:"https://etherealengine.github.io/etherealengine-docs/docs/devops_deployment/microk8s_linux#accept-invalid-certs"},"here"),".")),(0,n.kt)("h2",{id:"6-workloads"},"6. Workloads"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workloads",src:t(7317).Z,width:"1920",height:"992"})),(0,n.kt)("p",null,"This page will show current state of workloads for selected cluster. The workloads are mainly the k8s pods of various components of ethereal engine. In addition to ",(0,n.kt)("a",{parentName:"p",href:"#33-options-panel"},"options panel"),", following the sections of this screen:"),(0,n.kt)("h3",{id:"61-workload-tabs"},"6.1. Workload Tabs"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workload Tabs",src:t(1623).Z,width:"1195",height:"104"})),(0,n.kt)("p",null,"This section allows to filter based on various workload types. Default tab will be ",(0,n.kt)("inlineCode",{parentName:"p"},"All"),", which displays all workloads. The number below each tab's label will display the currently ready count followed by slash and then total count."),(0,n.kt)("h3",{id:"62-workloads-table"},"6.2. Workloads Table"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workloads Table",src:t(6490).Z,width:"1788",height:"377"})),(0,n.kt)("p",null,"This section will display data based on selected workload ",(0,n.kt)("a",{parentName:"p",href:"#61-workload-tabs"},"tab"),". For each workload, it will contain pod name and other details. Hovering over a container's circle will display further details. Moreover, there is a ",(0,n.kt)("inlineCode",{parentName:"p"},"Logs")," button to view kubernetes container logs as discussed in next ",(0,n.kt)("a",{parentName:"p",href:"#63-workload-logs"},"section"),". ",(0,n.kt)("inlineCode",{parentName:"p"},"Delete")," button will allow to remove the pod from current kubernetes distribution."),(0,n.kt)("p",null,"Additionally, there is refresh icon button on right top of this table. This will refresh/reload data being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval."),(0,n.kt)("h3",{id:"63-workload-logs"},"6.3. Workload Logs"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Workload Logs",src:t(6200).Z,width:"1804",height:"205"})),(0,n.kt)("p",null,"This section will by default display cluster ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs"),". Though if user clicked ",(0,n.kt)("inlineCode",{parentName:"p"},"Logs")," button as discussed in previous ",(0,n.kt)("a",{parentName:"p",href:"#62-workloads-table"},"section"),", then the logs of that workload will be displayed. The cluster ",(0,n.kt)("a",{parentName:"p",href:"#37-logs"},"logs")," will then be displayed under ",(0,n.kt)("inlineCode",{parentName:"p"},"Config")," log tab. User can toggle between these log tabs, while workload logs can be closed as well."),(0,n.kt)("p",null,"The download and clear icon button will perform actions based on selected log's tab. Additionally for workload logs, there is refresh icon button on right top of this section. This will refresh/reload logs being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval."),(0,n.kt)("p",null,"Beside these icons there is also a container drop down through which user can select the workload's pod container for which logs are displayed."),(0,n.kt)("h2",{id:"7-admin-dashboard"},"7. Admin Dashboard"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Admin Dashboard",src:t(1089).Z,width:"1920",height:"1012"})),(0,n.kt)("p",null,"Once, everything is configured correctly and all ticks are green on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"Admin")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the admin dashboard of ethereal engine deployed in your local k8s cluster."),(0,n.kt)("p",null,"You can perform various actions from admin dashboard including installing projects, managing users, groups, locations, instances, resources, etc."),(0,n.kt)("h2",{id:"8-k8-dashboard"},"8. K8 Dashboard"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"K8 Dashboard",src:t(9593).Z,width:"1919",height:"1004"})),(0,n.kt)("p",null,"Once, your selected local k8s distribution (Microk8s or Minikube) has a green tick on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"K8 Dashboard")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the k8s dashboard."),(0,n.kt)("p",null,"For MicroK8s, when you launch it for the first time then you will be asked regarding token configurations. You can use ",(0,n.kt)("inlineCode",{parentName:"p"},"Skip")," button to pass through it."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"K8 Dashboard Token",src:t(7728).Z,width:"1437",height:"336"})),(0,n.kt)("p",null,"You can perform various actions from k8s dashboard including managing pods, jobs, deployments, services, etc."),(0,n.kt)("h2",{id:"9-ipfs"},"9. IPFS"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"IPFS Web UI",src:t(8625).Z,width:"1919",height:"1009"})),(0,n.kt)("p",null,"If ripple stack is enabled and once, IPFS has a green tick on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"IPFS")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the IPFS web UI."),(0,n.kt)("p",null,"You can view and manage various aspects of the IPFS running in your local cluster using this dashboard. IPFS is not required by default for engine, though for custom use cases it can be used."),(0,n.kt)("h2",{id:"10-rippled-cli"},"10. Rippled CLI"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Rippled CLI",src:t(7083).Z,width:"1918",height:"1007"})),(0,n.kt)("p",null,"If ripple stack is enabled and once, Rippled has a green tick on config page (",(0,n.kt)("a",{parentName:"p",href:"#3-cluster-screen"},"Cluster Screen"),") then you can click on ",(0,n.kt)("inlineCode",{parentName:"p"},"Rippled CLI")," button in ",(0,n.kt)("a",{parentName:"p",href:"#32-navbar"},"navbar"),". This will show the Rippled CLI page."),(0,n.kt)("p",null,"You can run various commands against ",(0,n.kt)("inlineCode",{parentName:"p"},"rippled")," server and view their outputs. Rippled is not required by default for engine, though for custom use cases it can be used."),(0,n.kt)("h2",{id:"11-updating-the-app"},"11. Updating the App"),(0,n.kt)("p",null,"Every time you launch control center app it will check for the latest version of the app. If there is an update, then it will prompt to update. Its always recommend to use the latest version of the app."))}b.isMDXComponent=!0},1089:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/admin-dashboard-8da10eb1756744b7b838bf6a8b21171f.jpg"},8682:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/cluster-screen-6b4a15318bb6d140884510f33096e81d.jpg"},9478:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-1-69365b8bb443e1c2504ab4a664153aeb.jpg"},2725:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-2-0035fa39ad8da13fa2fda663f5947a3f.jpg"},9757:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-3-59573c2159d861239db5fabefa370f1b.jpg"},2718:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/configure-cluster-4-33272336d49d5be4f7211db5b3dd926a.jpg"},453:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-1-39bbbb0824dd3517c8bcb343ea41f5c3.jpg"},2569:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-2-8939ac555caaa3a25324c3277e05fc1d.jpg"},4910:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-3-268e34e5fd27d1d842e32293db9d9e30.jpg"},4890:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-4-6b65fcb7b64a996dd4497b50f191bde7.jpg"},2343:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-5-adcf4f008722a4a8c9bbb371848509e1.jpg"},9611:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-6-50f67da04a5f9089adb83ec1b6991940.jpg"},9015:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-7-7d4c7c284fbb0800e97282c7a3edc3de.jpg"},5847:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/create-cluster-8-855c605455aa6e8a0aa64f2b004aaf97.jpg"},4832:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/engine-launch-23f28e38012c96631d1526c3f0d5bad8.jpg"},8370:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/home-screen-d9cdf4c573c4f4ed8ff1686945481346.jpg"},380:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAdAB0DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD84f2RP2Tf+Gk73xRrXiDxRa/D/wCGPw7s4tQ8YeLLq1a7XTI5XKQW1vApBuLy4dWWKEMM7WY8Lg9/qX7ZnwN+GUj6X8Nf2XfButaNASq6z8UtXvtc1zUwCQJZYrSe2trUsMExR+YFOcOQRhn7Sl63w2/4Jlfsz+DtNZ4bHx1e+I/iJr23AXUb1btdMsg/HJtreCdVBPAuegPNXv8Agmr+whB+058Q7C/13VvhrN4auNM10f2RqPjG10/VTcQabdPbym1MizLGs6xyFyAu2NmPyg1+gVJxlGVau3yptJXtt6btv5Gepa8Hal+zz+3brkPhS+8I6T+y78RtVkWDQ/EmkapdX/gnUbpuEtdRs7gtNYK7bVW6hlkVC2XQKuG+a/ir8K/EXwN+KPiLwV4s0q40XxP4T1CXTNUsZfvW08bYIBHDIRhkcZV0ZWBIYGrXxp+B2ofBHWLXRtW1rwT4ikvrIXJm8Na/ba3ZhGLLsaWBmRXypJTOQCOxr2j/AIKU69ceOfgX+y78Sr6S4uPFPjD4cnR9avJvnl1JtG1G60yC4lY5LytbwxBnJJYpkk1opexceR3jLo9bPfrr95O50nwO8GXH/BQf9hez+Enh9ftXxm+Bmo6l4k8IaSX/AH3jLw/qAjk1GwtVx895a3FvHcJHnLxSSBATux84/Br4wa58APiQ/iDQVtrfW7G11DSZI7623+Qt1bTWdwjxtgrII5XGDgqwGeRiuf0nXL7wprVlqulX19peq6bcJdWd9ZXL211ZzIQySxSoQ8cisAQykEEcEV9Iax/wVV1/x5DHP8XPhV8D/jZrFvEsK+IPE/hNYdeuVjUKouL6zeCS4wAB+93E9TkkmqlTnSbSSlCXTqr7+qfyHzJnjf7Nf7M/jH9rD4tWHgL4e6T/AGtr14nmSNIxjtdKtlwHu7uXkQW0YOXkbtwAWwD6J/wUb+LPhT4hfEvwr4E8A6g2sfDf4JeG7bwPoOqtH5Y8QyQNJJfaqq5bal1eSzyIMnKbCMAhQz41f8FF/iB8WPhVd+BdHsfBXwr+HGpSrLfeFvh7oEPh6z1cqny/bnizNeYHaaRlJ+YqWAI8LQGLKjjacfLx0ranRqTmqtVWS2S1+bYnpsf/2Q=="},6290:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAFDAGEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4t/4d7f8AU3f+Ur/7dR/w72/6m7/ylf8A26vpKiv7v/4h7kP/AD4/8ml/mfM/W63c+bf+He3/AFN3/lK/+3Uf8O9v+pu/8pX/ANur6Soo/wCIe5D/AM+P/Jpf5h9ar7nzb/w72/6m7/ylf/bqP+He3/U3f+Ur/wC3V9JdqGO3rx9aiXAPD0Piopespf8AyRUcRiHsfNv/AA72/wCpu/8AKV/9uo/4d7f9Td/5Sv8A7dX0lnNBOKI8AcPNcyoq3+KX+ZMsVXWjPm3/AId7f9Td/wCUr/7dR/w72/6m7/ylf/bq+kqK0/4h5kP/AD4/8ml/mH1qva582/8ADvb/AKm7/wApX/26j/h3t/1N3/lK/wDt1fSVFZ1PD3IVFtUP/Jpf5gsXW7n5N/8AC9f+oWf/AAL/APsKK4PFFfhf9l0e34s9T2j7n7QUUUV/Vh4IUdKKaQGf71flXjB4lUuCOHZ5o1zVJPkpx/mk+r8lu+9rH33hxwRV4pzeGDvamtZy/ur9XsvvEBYnp8rdCe9K43nDfMeuD27V7R+xl+xJ4h/bL8V6ha6XcRaRo+koGvtSki8xImbOyNVBUu5wf4uMHOK+lPhBcfsp/BPwFDpPxG0GH/hOtPmex1i0mhuL9lnjbY0iNjaI2wHwpH3vWv8AMLOOIuKeK68swzrGuFOWq5pOMUu0UnZW8kf2RGvw1wt/wm5Rg3WqwtzqnFSmr/zPfW2u9rrY+NfhF+zn43+PI1A+D/Dmo64ulp5l08AULEDkgbmIBY4OFBJOOBXI3dvNpt5Jb3UUlvcQuY5I5F2ujA4II6gg8Yr9aP2aL/SPCF94m1P9nux8NeMPCPiB0updLbUm0+50W7WMIcq8bN5Um0N8wyGztyCMfl/8dzrVz8a/GEviTT10vxBPrF1NqFoBhYJnlZnC/wCzkkgjggggkc19lwz4kcQcBSw+MwmLnWhKTU4SblTcVty30T7NO/5Hx/8AZeXcdYrFYHE4WFBxinBr3aqb3U49V3vp27nK0UyM84p9f6fcJ8TYTiDKKGb4H4KqTX5NP0ejP5B4gyTEZRmNXLsT8dNtevZ/MKKKK9+p8D9Dx0fi/RRRX81HsH7QUUUV/TB44V7l+wL+xk37a3xB1TSpNcXQtP0e0S5mlVPNmk3MUAVC2OgzkE44z1FeG1tfDf4o+JPhLr/9qeGda1DQ9SCGL7RaylGKHGVPJBHAPI7Cv4v+mDS5cJleMxMHOhGpNTS2vJLl/Jn9FeAcMRX/ALQwmXVVTxUoRcJPok3f9D9GLvVbr9gv9gr4qeEtEkX/AISLwpq4sP7Ygj2/ajepBItyT0WRIZVQgE7WjT1FfmdcXElxO0kzySzTNvd3Yl3J5OS3JJ9zX6N/8E/PF/h39s/9kXxt8JfE181v4qvJpb2e8mlDXGoM7h4rrceXaNkVT/sxpz83HxD4m/Zi8Z+H9TvksdB1bXtLtL6Wxh1TTrKWazvGjkKEo+3nBUg/Sv4j4so1MVh8LXwWtLlsktbO/W3ZWV/I/cvDjE4fLsZj8Hm1o4n2ilKctOZNKzTfd3aXn6mp+xd8ftQ/Zu/aH8O6/Yy3C2Ml1Hb6lbQIZPtduzYdCi8u4BLKMZBUEelek/8ABVP4g+F/ix8e9P8AE3h2z1qzm1PT1j1AajpU2ntJJGSiuBIqlsqQpIz90DrXb/8ABPD/AIJ/axbfFPR/HnxMiTwfoGh3K3dhaapKLa51K4XlPkcghFba3zAFsADIJrzn/gqD+0jp/wC0Z+01dNos32jQPDMX9l2cy4KXMisfOlXHVWI2j1CKR1rnqYfE4Th6VLFvlUpJxi99N3rt9x2UcZgMw44hVyyDk6dNqpOMvd12Tsvefz/I+cE/1jU+mxjc5p1f6Y/Rgw+JpeH+DWI+05tejm7ffv8AM/lfx0r0KvGGI9j9lRT9eVBRRRX9AVPgfofj5+L9FFFfzUewftBRRRX9MHjhTSMHd3p1FfHcd8E5fxXk9XJszXuTWj6xfSS9Hb12PpOE+KcZw/mNPM8E/ei9V/MnuvRoueGfE+peENYj1DR9RvNK1CEEJc2k7QSoCCDhlIOCCcjOOT6Cvq74A/8ABYHxd8B/hrYeF18I+G9TsNLiEFsyeZbsFHdgCQzMTknjJ5xXyG0Wfu/LSYZfQ/jX+dOefRz8QeHMXJZKvb0fsyi46rpeMtU/S68z+uafifwFxPhYvPI8lRWvGSktfKUeiu7beh+jP7Lf7aPwx/aW8VeNvEHxsj8M2up7Y4tLsdVjWa1tLLysMkHmA5dnLFyfmO5RyqgD4D+KNxot58TPEUnhuFofD02p3DaZGw2slqZWMSkdiEK+/FYRjYkZK4znv/8AW5+lKsaovH1/Gvs+Dfo3cU5/VoLiumsPRpy5m006k/JJOyT/AA7Hx2YeJPDXDVTEVeGZyrVKsVGMXdU4W0vqrtrf9Ry/LRRRX+gmVZXhsuwdPAYOPLTppKK7W29dN33P5fx2OrYyvLFYiXNUm7tv+v8AhgooortqfA/Q4z8X6KKK/mo9g/aCiiiv6YPHCjoce2fw9aK9e/ae8NaX4e+HXwem0/T7Kxm1PwiLi8kggSI3U32y4XzJNuN8mFA3Nk4A5rzcZmaw1ejRkr+0bj6WjKX6FUY88pLtG/8A5Ml+p5DigfMeOT2A7/T19fpzX2hqA8L/AA2/a18N/A//AIV74R1bwtMNP0XUL2XSEk1i+lu4Inku1u/9ZGyyT7gEIVFjOBXG+MtM0v8AZC+Avh2403w74V8Ua94p8Q6xbXWpa9pMOppDb6dcLbxwwxyhkRXyZCwy3OM4C4+To8cSqThRp0X7SryumnJWcZKTTk+jUYt213S726Pqvn/W/wDXmfMI5/PH+f5fWg8D04zzX1P8B/AuhfFf9pbxb460X4Z6hd+FfCmjHWl8JSWBvI7y9liVIrVYlDFoXnZ5VwuAiHIAGK1NS/Zy0v4a/tCfHHTrrQYf7Kb4fal4l0CG/sVR7BZjDJDtV1zHJFueEMAHDRsPlINOtx9haNV4eVN86hGTV43TbScfVKSb6O/kNYOUtV3t8j5EooYbRzwMZz2Ior7tSTRyBRRRSqfA/QD8X6KKK/mo9g/aCiiiv6W549zyLMK9Qvf2mE8QeD/Dej654D8F68PCun/2XZXd1LqkE4g3vJ8wt7yKNm3uxyUHWvL6K8/HZdhsYo+2Xwu8WpOLWlvstPZtDptxba6q3yunb70j27QP28PFGg2uk3B0HwXfeKdBsBpun+J7vTXk1e1iVGSIh/M8ppI1ICu8TMABkmud+H/7Umq+Dfh9/wAIvqmgeFvGmgxX/wDaVraeILaa4FjcMQZHjaKWJgHwNyMzKSOnLZ8zorzo8L5Tyyj7NLmad03dWu1yu94pXekbbtdTT2s/6+78vw0PTvib+1t4s+LXh7xFp2rDTFXxVrEGr39xbwNFK/kQ+VBaja237NGCSi7SwPJJyRWl4L/bR8QeEPD+naZNofhjWrbT/Dt74VZr+O68670+5mWZoZJIp42whBEZUqVVmGScEeP0U58M5RKj7CVGPKnfdqzty3VtdtLdkgjVqLb+tb/pf1Nzxz4t0/xZdwyaf4X0LwusKsHj0ua8kWYn+JjdTzNuHoCorDoor2sLThQpKlCXu+bcn/5NdkSuwoooq6k48j16Csz8X6KN1FfzZc9Y+jP+F3eNP+hu8T/+DSf/AOLo/wCF3eNP+hu8T/8Ag0n/APi65eivmf7Txf8Az9l953ezj2R1H/C7vGn/AEN3if8A8Gk//wAXR/wu7xp/0N3if/waT/8AxdcvRR/aeL/5+y+8PZx7I6j/AIXd40/6G7xP/wCDSf8A+Lo/4Xd40/6G7xP/AODSf/4uuXoo/tPF/wDP2X3h7OPZHUf8Lu8af9Dd4n/8Gk//AMXR/wALu8af9Dd4n/8ABpP/APF1y9FH9p4v/n7L7w9nHsjqP+F3eNP+hu8T/wDg0n/+Lo/4Xd40/wChu8T/APg0n/8Ai65eij+08X/z9l94ezj2R1H/AAu7xp/0N3if/wAGk/8A8XR/wu7xp/0N3if/AMGk/wD8XXL0Uf2li/8An7L7w9nHsjxeiiiuX2s+7JPaKKKKzNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKKKACiiigAooooAKKKKAPF6KKKDM9oooooNAooooAKKdBBJdXKwxI0kjkIEVcszH7oA65PpjPtXrHhj9gX47eN9MF7ovwU+LWsWbDK3Fj4P1C4iYeu9ImFTOpCLtJperA8lorqPiV8EfGnwYvVt/GHhDxP4TuHO1YtZ0uewdj7LKikn26e9cvjCg9B3JBx/n3yRSjUjL4Xf0AKKKKsAooooA8XooooMz2iiiig0Cvsj/glp/wR68U/wDBQ+41LxVrGrW/w9+DvhV8694s1ELHF8gDyQW+9ghkCHczsfLiBBYk7Ufw/wDYd/ZS1j9t79q3wX8L9DZobrxTfiK4uAuRY2qKZLi5PbEcKu2D1IAHWvt//gvD+3PpvgV9N/Y/+C5/sH4R/CFE0vV1tJSG1rUY+XimfILLDIW35B33HmMc7Ux5+Mr1HP6rh/ie77Lv/kV5na+K/wDgr/8As2/8ExYpfCv7Ifwd0PxTr2nBobj4heKY3lNzIu4M0Zws8kZIzkPbx8HahBBrwfxV/wAHLP7YHiLVGuLP4h6ToMLHItbDwtprxJ/s/v4ZZP8Ax6vgv/HP+f8APpSD5gvT+ZH4ZySO+PWphlmGj8a5vN6/mSfpj8Iv+Dob40W1udH+LnhH4ffGLwjfBY7+y1DSksbi5TuoZFMGPZrd69A8Vf8ABOr9m7/gsp8NdU8a/sj3UHwz+LGkwi61f4b6rItvb3mBz5A3ERAscLLETByqukLNlfyPAwTwOevHWus+Bnxz8Vfs1/FjRfHPgvWrvQfEnh+5W5s7yByCGXhkcchlYEqysCrKSpBBIqamWqD58M+SX4fcVzIy/H3gLWvhZ401Tw54k0u+0XXdEunsr6xu4jDNbToSGRlPQgjGP1PU49frB/wVr8DeG/8Agp3/AME+PCf7a3gbSLfS/F2kvH4d+Jum2hJWGWMrEsh4JLRvJFhmyTBcw7j+74/J+unB4r21O8t9n5MJaBRRRXWSeL0UUUGZ7RRRRQaH6kf8GyOm2fw28Q/tG/G25t47iX4R/D2SaASD5UaVZ7kt7Hy7Blz2DkdCa/MPxF4hvfFviG/1bUrmS81HVLiS7u7iU5e4lkcyO7erFiTn1NfqF/wbiQ/8LK+A/wC2d8LrRt+tePvhyVsol5eXbb6jatgdwGv4h9WFfli3yjPIxgHP06/1/CvLw/8AvlW/91fKxX2SxpWkXeu3n2eytbi8uCMiKCNpJMDG47VBPHTpjpzX6Lf8EFfhpfRH9qCbVvD96PL+DGsrbvd2TfJL8mAhZfv/AC8Ywfavjf8AY5/bQ+IH7CHxXl8bfDXU7XSPEU2nyaW1xcWUV4q28jIzrskVlyTEO2R2xk5/Wj/gkJ/wWg/aC/a0l+PbeOPFWmaoPAfwx1PxJo6xaJa26xX0Gzy5D5cal1GT8jZB3c5wKjNqleNJxUVbvd/5DgfizdfDzxBZQSTTaHrEMMKGR3aykCooBJLHHCgAnOAKxwcH+tfaHxr/AOC//wC0/wDtA/CfxD4J8UeNNIvPD/iqwl0zUYI/D1jBJNBKpR1DCMEZUkZUgjqCDXxfXfhpVnD9+kvT+kQfqp/wbZ3x+PPw/wD2nf2fdQY3Ok+PvAsuo20D8i2uI91m0qDs266gII6eTHjGK/Kuv1P/AODWCD/hAPjt8dPildfu9D8B/Dm4S9mPCx+bcRXQyex2afIfopr8sK48NpiqyW2n5FdAooor1CTxeiiigzPaKKKKDQ+ov+COH7bkP7A/7fvgzxtqUjQ+F74vofiHH8Nhc8NJjv5Ugjmx3EJHU12f/BdH/gnxdfsQ/tj6tq2i2gk+GPxLml8QeFdQgAa02ynzJrNXBx+5eT5Rk7omiPViB8Vdf0/Tp/8Aqr9NP+CcX/BT/wCF/wAaP2Yrf9ln9rW2kvPhyrRw+E/Fqg/avCrjKxI0gBZEjz+7m2kRgskgMP3fLxUJ0qv1mkr9JLuu/wAjQ/Mv/wDXmu8+B37Tvjv9myPxQvgjxFcaB/wmejzeH9aMUMUjX1hL/rICZFYqp9VwR2Ir7G/bS/4N3vjN8Aw3iX4XwxfHL4a3ym503VvC+26vfIbJTzLZGZpDjHzW4lQ9cqTtHwp4r8Aa74C1Q2GuaJq+i6gp2tbX9nJbzA+m11U11UcRh8RGyafl/wAOTysyMYHb04FPtreS9uY4YY3knkcIkajczk4AAUck5I4GTkgYJr2T9nb/AIJ2/HD9q/Wrey8A/C/xhrq3D7ftn9nvbWEWf+el1Nthjx7vX6R/Bf8AYn+Bv/BA7RrH4p/tIa9pPxC+N0Ma3nhTwDoswnTTp8Hy5n3AZYNgfaJFWKM58sTOFNZ4jHQp+5H3pdlu/wDIFG+5k/Gjw4P+CMn/AAQzb4c6sPsPxw/abuDNrNi3/HxpOmAKHik54VYP3RBBPm3kwGRGcfkXXrf7cH7ZvjP9vj9ovW/iT45uY5NT1UrDa2kIK22mWiHMVrAD0jjBbk8szOzEszE+SU8Dh504uVX4p6vyfYkKKKK7QPF6KKKDM9oooooNAo/znFFFAXPbP2UP+Cjnxt/Yiuf+LZ/ETXvDliz75NMLrdabK38Ra2mV4d3J+bZu5619leGf+DsP9prQtJWG60X4R61Io5ub3Q7tZH/2sQ3kSf8AjtfmTj+v69aP4t38Xr3rjrYHD1XeUVf0HzM+8fjx/wAHJH7Vnxv0uWxt/GWk+BbO4GyRPDGmR2km32nkMk8f1Rwa+HfFHirVPHHiC61bWtSv9Y1W+kM1ze3tw9xcXLngu8jksze5JNUP8/WitaOGp0VanFL5CuwAx/8AqooorfYAooooA8XooooMz2iiiig0CiiigAooooAKKKKACiiigAooooA8XooooMz/2Q=="},8625:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/ipfs-web-ui-4aadbd2ae4cfad15fbb1021da5dcbc8f.jpg"},7728:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/k8s-dashboard-token-b62d88f9fbe1ee0472b6f62e41abb1e5.jpg"},9593:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/k8s-dashboard-2382bfe675c6cbbe0268526c1e20076c.jpg"},2038:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAhAB8DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8G8UV2H7P/hXS/Hfx28E6Hren+LNY0bWddsbC/sPCtutxr19BLOkckNhEwKveOpZYkYbWlZM8E1+nw/4JXfsvOuX/AGc/+CtmW5B/4QDST+vkV+j4rMqWHnyyTOTlZ+SNFeufty/Crwv8E/2p/FPhjwX4d+LXhLw3pv2QWelfE7T4bDxVa+ZaQSv9rhhVY13SO7x4UZhaNjkkmvI67KdVTgqi6iOu+AXirS/A3xz8Fa1rmpeLNF0XR9esb3UNQ8L3C2+u2NtHcRvLNYSN8qXaRqzRM2FEgQk4Br9A/wBpn/gqh8NX+B+tf8Ka/aQ/4KWL8SP3B0o+NfH9r/Yg/fxCcz/Zbjz/APUGYIE48zyy3AavzOqSKTZt6KufmOD/AJ/w6jmubFZfCvNVJ6lczP1M+Bn/AASH0P8A4KW/APw/+0xq/wC0L4t1jQ9HsLmX446l4qs7i/8AEGjT2EHmsLLPnPeRi0SCJGZnIEasBktaw/l94qh0238UalHo1xfXejx3Uq2M97CsN1NAHPlvKiO6pIVwWVXYAkgMw5P1V8Ef+C2v7QX7PGm/CnTfB/i638P+G/hHazWun6FZWCW+ma2J5Gad9SgQqt27qVTdJyuwMpSR5JG+WPGXiebxp4t1TWLi3sLSbVryW9lhsbVLW1heRy7LFFGAkcYLEKigKoAAAArHB0akJtT+HoErdDNo/j/GiivW6Eg/+qP+9/Sh/wDW0UUMD//Z"},4783:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAhABwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8HSuMcfe5+tIw2nkH+X+e351Ijrj5mxuHX8cn/DFf0f8A/Bov+wz8Tv2VPh98XPF3jjQdP07w78ULbw9e+FtQs9d07VINVigGpea6mznl2hPtEIIfacsQBkMB+jZpjlhqXMtzmjG5/N7Gu87QGbd04yfQfrTa/U7/AIOmP2H/AIkeA/8Agol8RvjXq2h6fp/w08cXWk2eganJrlh5+qTQaNZQTCOzExuiI3hkDN5QAwD91lJ/LGtcFiFiaEZvcl6BX6+/8EVf2m/20P8AglPqmoeHdT/Zj/aG8c/CfVhLcyeH/wDhCdVjm0272/LPaO0BEe9lVZEOVZcEDcMn8hoxnHrj+v8An/63Wvdh/wAFVP2nl+7+0d8fF/7qBq3/AMkVjmOFq11yRSa8/wDgDjKzPWv+Cq17+1v+138Ude+NXx0+EvxY8K6JZmOCE6p4S1PT9E8M2ryiKG2jkmiCRqzyKNzMDJI5Odzha+K69g+Jv7fHx1+Nngq98M+NPjX8WfF3hvUvLN3pOteMNQv7G6MbiVPMhlmZH2yIrrkNtZVIwQK8frXL6dSlT5ZJL0FLUavRvoP50P0ooruETr/WP+VRUUVUQP/Z"},8121:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/logs-bc60f219e2a36428a0a6d5a10d85dab1.jpg"},6072:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAC4DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6ByccknJAAyTjr/AIUV2n7Pnwcf48/FvSPC6+I/CPhGPUpwLjWPEusQaXpmnRggtJLNMyq21cny1y7HhVY8V+nVKihByl0MY6h8BP2d/HH7UXxAj8K/D3wvq/izxBJBLdCzsIC7JFEoLyOThUQblXcxALOijLMoPJ6tpV1oGpT2d/b3FjeWsnlTwTxtHJCwJDBlIyCMHIIzX9YX/BOj/gmX8O/+CbHwj/4R/wAI2/8AaGualHG2teIbyNBfaxIu4gEgfJCpaQxxAkRhjy7Fnb5b/wCC8/8AwR68A/tLfDjVPi9puv8AhX4a/EDQY4zfaprV9Hpuj6/GzRxRQXU0jrHDMz+WkUpI3MyxNwVeP52lxAnV5JLTuU4dj+dnGOvFFTalp76TqM9rK8EklvI0TNDKksbFSQdroSrKccMpII5BI5qGvpFZq6Mwo3kscE7vujHYbcL04BBxx1/iPBzRSyjyz/ezuzn2GR+v5VNSClHkfUqLsfvv/wAHCv8AwUr8NSfsX+Ff+FE/HzRW8Xf8Jpam7/4QPxvGdQ+w/YL/AH7xZT+Z5Hm+Rkn5N/lZ+bZWH/wUA/bi+Hfxg/4N2rXw1J8X/BviX4nX/grwiNR0x/FNte69c3qXOlveebD5puGmVkleUkF1KuW5Vq/CCWdvK3H5id5+Yk/dYD9f8OmBh2nv9shG4bVaURkAnBGQvQ+x6dOBxivAp5HGMU77O4/aDiTn0z1Gf0pKB0or31okiD//2Q=="},8e3:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAkAJgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6x/H2q3GieEb27tZBFcQiMo+0NjMiKeCCOhPatiuf8AikceAtQ4/wCeX/o1K/TpXtoc5523xZ8RKP8Aj+X/AMB4v/iaT/hbXiDbn7cn/gNF/wDE10uqaFZatosdxqMdukcgCLrWloJIVbAwk8QwVPYkYPGdr1it8Ip7T/SLvUNNt9HzlNRWcSRXA9I1X52b/ZIBXjdtrengcRNc0Ff+vw9Xp5nRiMO6UlG97/1/XQqr8W/EJH/H8o/7dov/AImt/wCGvj7VvEXimO1vLpZoGjdiohjXkDjkKDUOt6PDpHhCdrSzt7G1mUCO81ID7ZqQ45ij52IeuRnHTeelZvwbH/Fbx+0Mh/SueUJwnyyFWw7pWu73R62G4pwNfQ3wI/4J4XvxQ+Aun/E7xh8Svh38HvBWva23h/QL3xZPcmTX7lOJjDHbxSMsMRKq80m1FO7JwCax/Hn/AATj+NXgn9pTxh8J7b4feJvFXjPwMynVLbw3p02qrHDIqvDcAxIT5UqOjKWCnDYODkVh9co87puWq3/ry6mGtro8RJpN1emeA/2LPjF8UtR1e08M/Cn4ja/d+H786VqkGn+Hrq4l068Vd5t5lVCYpAoLbGAOMdBk13fhP/gl58YPE/7MfxO+KD+E9d02x+FOoRafq2kXekXceoTNk/amRTHtVLRBvnZyPLXk4qpYqjF6yX39w9T543UbsivU9W/YV+N2gaxomn33wf8AidZ6h4kna10m3m8NXaS6pMsPnFIFKZkYRZkwucLyeAa7T4A/8E4PGHxQ+K3xE8F+NI/EHwo8QfD/AOHmqfEF7PXPDkpub6KyETLB5UkkDRrN5hxN84UoRsbnafWqSjdyWn6bjSPnjdRmvV/2QP2P/EX7ZHizXLPSdR0Hw1ofg/RpvEXiXxHrtybfTPD+nxAbppWVWZiSQFRFLMc44Umuo+Of/BOrxb8L9F+GuteEdX0X4yeGfi089r4Y1TwZBd3Bvb2BsTWLW0sSXEdwvXY0YJAJHKsoJYqlGfs5PUVr3seA5pN1eo3P7DvxosviQ3g2X4S/EmPxZHpba0dGbw3di/8AsKyCNrrydm/yQ5ClwCASASCQK9G/Z7/4JJfHH49/GPV/A83gXxV4L1nRvDs3iOYeINBvbcGJVfyYgoiLCS4eOSOLIwzxuAcjFS8VSSu5L7ws0fNG7FG6vSfDP7GXxh8Z6J4i1LSfhR8RtSsfCN3c6frlxa+HbqaPR7q2z9pguGVCI5IcHzFbBUqQdp4NG9/Za+Jum/B+L4hXPw78bW/gGaCK7TxJJotwmkvDK/lxSC4K+WVZ/lB3YJwO9X9ZpXtzL7x2Zwuc0UDpRW4grn/ikceAtQ/7ZYz/ANdUroK574rcfD7Uj6CP/wBGpUy2DYzrSX+x7O3vGkt9JkmURpqWnR+dp13kZ8q4ixwf7wx0HKHrU50KTSlbUDouh6TI3J1iS58/TeM/PbRchpD3AL4I4RO3mnhrxjfeFrpntZdiyDbLGyh4pl/uuh+Vh9RW9/wnuk2ca3VnoMUWpnBBmmM1pA3do4mHU8cOWAx0Nezl2OhCk4Savb+un5WO6tioVXGVrW/rpb9DU8WKtz4YuryNDdLcctqurP8A6ReHIBECZOB7/Mf9pelYvwcBHjiPt+5kx7cVz+teIrvxBetcXk0lxM38TnOAOgHoB2A4FdB8GH3eOI/+uMn8q8WpU56nMY4rERqyVuit/X9P1P1C0G9+Hn7eP/BOv4L/AA51H4veAvg/40+Buq6va3cXjGae2stX03Up47gXVvJFHIHmjKbTESmcHJUFGPaeH/GfwT174AfGr4E/B/4+Xfw3t5PH+j+I9E8afEC/lsH8WadaWogmie6tbdGUx3RNxBE0SllSM8Hey/nNtyRnnb0Pp1/xP50gXBH+z0HoPSuCpl7lKUlLRu9vO9/zOe+iXbRemv8Amfqd+3r/AMFDPh38Vfgj8eovAPxDWPVNf+Ing9Ybi3uZNPvvF9vp2nQwXep+WCHaEzxLyxOfKjYgHBrU/bz/AGp/hX+0PYftveH/AAv8WvBNrceNrzwl4k8N3FzfyxWfiNdNtUN7bWsiIwe5dk8sRkDe7AEhcsPyewfX8vy+v/6z6mjGB8vy/T/P+eR0rnWSwVkpP+rfqhzlzWP1v+KH/BQnwL44/wCChHxa0mH41R6X4T8e/BWPwX4O8VHVLmfQ/CesyWEG+TKFvsoZ0kR5YlDBn5+8ao+F/wBr34V/DPwv4b+HeqfFbwn4w8ReAv2bfGfhHUfFlpeTTadqWpajcW0lhpFpczIj3BijidVO0KAcKF+ZF/J4Lg8cf5/z/wDXpCu7/d9P8/h+Qqo5TFPfp/n/AJjjLlVl5H1h/wAEwPjB4I0n4d/Hz4Q+O/FNn4Btfjh4Pt9K0vxPfo7afpWo2U7XECXRQMyQSlyGkAITYBjnNe7fsGeIv2ef+Cb/AO0z8ObjUPjDpvjjxl4g8P69p3iHXdKae88E+C7i7hEdi8LpFBePI2JI5pY3Uokv/LMEsPzbx/n1puzIwcFT1GOD+FdFbAqpJvmaT3S9LBF2XL53P1u8I/t46H8NLi88M6x8UP2d7NfC3wQ8c6X4Zufhlca2INP1G/ls3tbNNQ1G4kkmmkaEyRRxFGibcMkFDWX+zJ+2j8MbXRf2TdN134oaFpmqWPwf8b+DfEN9f6hI66Fe3jRf2fHfOoZo1IWTYWHy8Beor8pgMDH5+/8An8qXtjqPQmuV5LBw5W+z/B/5hza3/rp/kfrh+y1+234N+Gn7MXwK03wz8UP2cfDnjT4A3euaZr1341fxBM1zK87n+1NHj0+eFNRiu4z/AMtY97hwDg7kPyn/AMFE/wBrS1+LP7Jn7NHhXw140Wa00jwhd/8ACT+GtG1CWLT9Ov5L9pUjmtd5UMqbdgkBYIBzXxyVyu3Jx9f8+/SjbxW1PKacavtW7u9/z/zKjUsreX+Q5aKKK9QzCq2q6Xb61p8trdR+dby4DoWK7sEEcgg9QDRRQBjH4VeH9v8AyDV/7/y//FUL8LPD7H/kGr/3/l/+KooqYxQC/wDCqfDx/wCYav8A3/l/+KqzpXgbSfDt6tzZ2awzfc3ebI3B4PBYiiiqsrga69KWiigAooooAKKKKACiiigAooooAKKKKACiiigD/9k="},9026:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAC4DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8mutaPhHwhqnxA8V6boOh6featrWtXMdlYWVrEZZ7uaRgqRoo5LMTgYrNPzH+dffX/BBrws/gTxX8cPjvJo8eoSfBL4f3t9oU11aNJZw65cDZbMzD5MqiS5UkHbJuGNpI/RsZXdGk5/d6mEdWdN4J/wCCEHhP4cOul/Hb45Q+E/iDNp8WqT+B/BPhu48VatpFvIAc3htw2xvmUYWMpw215AwI4H9qD/gi3feD/hbrnxE+CHxE0744eDfCwDeIbGLTZdN8S+HMjfm5sHy5QIdxb5G+8dmFJr6C/wCCin/BQPUP2Zfg18KF/Zt/tT/hGdN8Wy6z4m+LkdoUtPid4qhST7YGkOGuonlluJHJ/dSfKsGYoBXsVr/wWF034i/ED9nfx34s+Dfij4Y/FPx5eWWmrrUFlbT6L8QPD13cRWt9BK7OJTDnZPAHR2R4U2sI5XZvn44rGpRrN3Te3oacq2Pw5V93TmnV7p/wU1/Zw/4ZM/b6+K3gODTrjS9J0vxBcXGjQyxlB/Z07edbbM/eURuqhhwTGe+RXhdfS0aiqU1UXUyGn+npmvvP/gn3/wAFH/AP7Pv/AAS2/aM+CfimPVrXxL8Qlmu/D9xbWpuLa7eW0igMMjBsoytEG3Hgq/XK8/BpGfx4oB3En+9yffnNTiMNGtHll0af3BHQ7H4c+GPiD8e7jRvh74Xs/F3jKaOSe80zw5psc14Vk8vdPJFbLn5iiEsQM7UPYGvpj9mn9gT9qEftIfCFvEnwh+Nn9h+EvEWnCBtQ0G+Nro9qt4kkgQuu2KMEsxxgcZr5Z+E3xe8U/AXx5a+KPBev6n4X8RWCSJb6jp0vk3EKyI0cgVh0DIzKfZiO9eut/wAFXP2mHRlPx0+JW1sg/wDE3YZ/SubEU6z92la1upSaue4f8HJXxx0740f8FVfFdrptvLCvgXS7HwxdSSY/0i5iElw7LtJ+UC5VRnByjeuK+D+an1nWLzxLrN5qWpXl1qGo6hPJdXV1czNNPczSOXkkd2JZmZmZmYkkkknJqGunC0VRpRprogk7s//Z"},2764:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAeADEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6M0U6KNppFRFaR2O0KoyXPQAD19q/UDnCKNp5VjRS0kjbVUcsx9AP8APUVs/EP4beIPhJ4rn0LxRouqeHtatVR5bHUbZ7e4jV0EiMUcA4ZGDA4wQc1+0/7CH7JNl+yN+x/8EbXUPgD4N8UftRfEzWL258Lf8JLCI49Lt4c3H2++kAZ44beBozsC+aXkjUBWII+gfiN8Obr47/tF6P8ADP8Aas+C/wAGNc+IXjjwxqI8C+NfDcdxNY3U1pEZZtPkS6UzwyRCTzlZmaNl3Yw25R4dTOVGpZR0733SNOTQ/m89P9rp7/Siuq+N3wS8Vfs6/FTWvBfjTRbzw/4k0G5a3vbG4TDIRghlIyHUqVYOpKsrKQSCCeVr26clKN0Z+QUUUUwCnRStDIrqzI8ZyrKxBQjkYOeMeox+nLaKAP3K/YS/azsP20v2VvgNe61+0D4T8L/tS/DXXb208Nt4gZZ21yCbNv8AYL2LcrSC6hESecp87cqsN0jHd718S/ib/wAKL/aS0z4k/tUfGD4KaH8QvAvhvUm+Hvg7w7JOlraNex+VPfzNdHz5ZJTCYUG1ECiTG5i2P5u4pzayh0Zo2U8MnBHp39efb9a2PiB8RfEHxY8W33iTxVrWreI9ev8Aa15qWpXT3V3cbFEa7pZMs21URRk8KqgYwMeHUyZTqcyl7rv8r9PzLVQvfGL4xeJ/2gfifrXjTxnrV94h8UeI7g3eo6hdvuknkPAwBhVVVAREUKiIqqoVVAHM0Hqf196K9qEVGKS2RAUUUVYH/9k="},6424:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAdADEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8m6WKCS7uI4YY5JppXWNI0UuzsxCqoUckkkADqSQByaSvtj/ggH4K0nVP27dS8b61aw6ha/BfwNrXxCis5AAt1PaLDDEA38LK10JAexjHWv0nFVvZU3U7GMdzcsf+CRnw5/ZS8E6Pr37Xnxq/4VTqWv2ou7LwJ4bsBq3iZYT0kuGxIkJ4+6InHON4Ksov+Hf+CZf7L/7Y8dxpP7Nf7TF9P8QsldN8KfEHSl09tblB/wCPeG4VIgkmBx+7lLEKCFBLro/8EWvjVZ/tJ/8ABSH4j+PPiLqWgap8ZvFXhzUdU8B3fiwhtLTX2ljeJdrcI0cfywIMCONHVQCEA7D/AILzz65afs5/Aq4+NF/4LX9rW1uLl9fl8LOkdxbaWCXtTcNFwrodjIQQAxkKZGTXgSrYhVlScnd22tbvtbbu7mlon5t/Fv4TeJPgP8Tdc8F+MNHvNB8UeGbr7HqWnXK7ZbaTarDPqrI6OrD5WV1YEqwJ53sv1H86/QT/AIKw+IP+GrP2AP2Uf2j9YggXx34u07U/B3iK8Rfm1aTSrqa2juJD1aRmhmbPbzSOgXH59joPqP517eDrurS5nvez9UZ2syGiiirNixX1F/wR3/bC0X9ir9uDSde8WD/ihvFmm3XhDxQ2cCHT7zZulPB+WOWOF2A/hQgYr5dobr+NVWoqrB05dTnW5+pHx7/4I+fs7f8ABOnwzJ46+NnjD4pfEnwr4pv5rnwlYfDjR1kh/soyeZby3WoSFbfzGhaPpJGpLEp5gG5cP4F/8E+v2Uf+CrR1XQ/2bb742/Dbx9a27XVuPGmlpqmg3BXcWSW6tXlEWQMKWlDccI/Kj5i/Y+/4K2/H79h7w5/Y3gXx1O/hdi+3w/rcC6ppkJ6fuo5PmhHJJWJkUnkgnmuw/aD/AOC8P7Tf7RXgu88J3nji08J6Dcp9murfwnpqaO13H/caZCZlU7cERyKGUlTlSQfn5YXEqdubXo79PS36mnMjpv8Ags78WvB/g62+Ev7NHw71f+3PDP7POjSafqmqwyiS21TW7nEt20TLwwViwYjgPI6YGw18M/wr9RSRxhYto4UcADtR2/EV7uFw6pU+Rf8AD3J6kNFFFKxsf//Z"},1977:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/navbar-f8650b27a2df2a7fcc7d1cb5f5354d9e.jpg"},8082:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaABsDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Xv2av2dtW/aV+IK6Lpskdnb2sX2m/vZFLJaQggbscbmOcKuRk+2TX6O/Az/gitovxJ8HXlx4d+H/AIi8aW+lx/6bqRnYZIyGI2lVHKtwoONp6np5/wD8EKvCPgHxN4f8ZL468RX3hnT3kkLXllbC4leZIVNvER2Vi0pz6hRkZ3D9Bf2+fiL4s8C/tJTaPb3F94J0Xw/pemwaFZ6PeSWVstqtpEyujRlfNxI0qhznG3A75+F8QOKce8fUiqkoUabUeWDSk3bd+X5n794f8O4F4WlSp0YTxFaMpudVNwik7WivtPXWz06n5kf8FJf+CP0n7JzTX3hfWNI1lLXTYdVvbHT9R/tBIYJFzlJdqncoBZ0YEgHcpYV8JlcHtX9Cv7Y8uq+Mvhd8H/EHjLRdLsPEviPw9OLy5jkxd63aJKVhurq38lFjcoeCHfer5wOFH8/Xi+zt7LxbqkNrta1hvJkhJYnMYchefpivtvDnibEYuVfB4m8vZ8ri3vytJ2fmfE8d8O0MJh8NmFBKMqnPGSVuXmhJpuNujPVv2KP2qF/Zn8dXR1KKe68N62iw38MXzPEyn5JlHdlBYEd1c98V+s3wO/4Ko6fH4HhaPWPhz46t7W0hh0y78TRR3V5okUYYIkfnEPHtycK68EDkgDH4Xk/N/n1FPcfMv0H867uLOAsNjsT9fo1HSm97JNPTqmcfDPH1fBYJ5diaMa1KL91SunG71s1rby2P1L/4Kvf8FavCHxM1y7k8AtqE3iG80iDS5ZptZl1aKyZQRJOs8hPzFWO2NCVVssecg/lqdzndgNu5ycU1Tlo/93P86RRlRX0nDPDeGyuk3Sbcp2cpPdvb5LyPm8+4gxGZzhSqe7TpLlhFXsl8933Z/9k="},5401:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAkAFUDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8PfhV8L9S+MHjKHQ9La1jupkeQyXDlY4kUZZmIBP5AnmvVT/wT18YL/zGfCf/AH/uf/jFZ37CI/4v1H/2D7j+S19nN+Ff2f4c+HuU5zk8sdjVJz52tJWVkl5eYsHh41ZWkfIB/wCCfPi8f8xrwr/3/uf/AIzTW/4J/eLkP/IZ8K/9/wC5/wDjFfasnw38Qf8ACO/2r/Y2oCw8zZ5nlHd/x6/bN+z7/l/Zf33mY2eX827HNUfCfgvWviH4kt9H8PaPq3iDV7wN9nsdMspby6n2qXbZFErO21VZjgHAUk4Ar0cZ4d8NwjKdKTaju+dNL1fQ+xwXDuDqK9S/3nxsf2BPFw/5jHhb/v8A3H/xmmH9gnxYg51jwz/3+uP/AIzX3AnwF8eTWE10ngTxs1rBqo0GWZdAu2jj1IyLELFm8vAujK6RiE/vC7qu3JApuifs8fEPxck7aT8PvHmqrbI7TNZ+Hby4WEJLJBIWKRkKFmhljYnG14pFOGRgPjcZwzkVJNwqf+To+uwPBWR1P4kn/wCBI+H2/YM8Vj/mNeGvwluP/jNNH7Cfihf+Yx4b/wC/tx/8Zr7Wg+Bfjq80K+1KHwP40m03TbiO0vLxNBu2t7SaQRmOKWQR7UkfzodqsQzedHgHeuXeH/2c/iL4ySaTRvh7491iO3VzK1j4cvLlYgkjxSFikZChZIpI2z9143U4KsB8ljcrwFJNwnt/eR9hg/DPheavVm/P94l8j4nb9hfxQG/5C3hv8JZ//jVNb9h7xQo+XVfDznHCrLN83tzH3r7D8XfCjxX4C0XS9V17wr4n0HS9djE2mXmpaTcWdvqUZVXDwSSIqyqVZWBQkFWB6EVzinDL0618pjOWCvSZ9zl3gfwniqftIc8lrqp3Wnov+GPz91DT302+mt5VVZbeRo3Gc4YHBH6UVpeORjxzrX/X9N/6MaiphK8U2fxhjIxpV5047Jtfcz079hD/AJLzH/2D7n+S19l3KebEy7tu5SMjqK+JP2M/FWm+EPjhb3OqX1rp9rNaTwCa4kEcasyjAZjwucYycCvrx/jB4PP/ADN/hP8ADWLb/wCLr+pvCHMsHR4dlSr1Yxl7SWjkk9o9Gzsy+SU9WfVr/tF+GU8Yf8Jwvie82/bf+EgXwd/ZDm7/ALV+wGz+yG64t/7LwAhO7zPs58v7OW5rxf4LfEu0+Ft3r8GpaTca5ovijw/deHNStre+SxujbzGNt8M7wzpHIskKHLQurJvUj5+PNH+L/hAj/kbvCn/g5tv/AIuo3+LvhEn/AJG3wt/4N7b/AOLoqZXkmHo1KEa6lGaS1nHRRvZJxs9L76vu2foGW1MPJcs5rXzPrjwp/wAFGLbwd4y0nxDD4Dv7rVtCxp9mb3xfNew/2T/wkcOvm3m8+3kmmvDNEYfthmC7WVjbs0aYyvjF/wAFG9U+L3wivvDt54N8OLq2qWFvZ3+q3Vva6lFfSRXt7dPdtaXNq8a3U32v55kIfzUeZSrSlV+Vn+LPhLH/ACNnhf8A8G9v/wDF1FL8V/Cf/Q1eGOn/AEFrf/4uvzvHcP8AD8Z+0jytp31m359ZP7tj7TLcHk7mpzlG6d9Zf8E+qta/b+sdctZLi6+Hyza9Y+euiXp8QEQaek32Fn82EW2+Zt9mTlJoVZZQrrJ5asdnQf8Agp1ZeCbi1h0f4YwPpdnq0OtW0Wr69HqN1aXK6rfalJLDN9hRElWS9X7PIYWMLW6O/n5K18bt8V/CpX/kavDP/g1t/wD4uo3+KfhXP/I0eGun/QVt/wD4uvi8xyrK0mo2/wDAn/mfdYLKeG6seWrKLXb2jt93N/XzPZf2kfj5pfx+k8N3Vv4Wfw/qmh6RY6Rc3AuLCZdQS1sLWySRnh0+3uXYraK3+lXFzsDlIzGvB8tH31rIb4oeFz/zM/hv/wAGkH/xdRH4oeF4hubxL4d2rySNShJx9A2fyr5DGU6VOPJS29bn65w/jsly/Cxw1CvTjCKdlzp2vr1Z8WeOf+R41r/r+m/9GNRUPiy8TUfFOpXELb47i6lkRv7wLkg/lRSp35V6L8j/ADrzD3sVUlHbmf5mbRiiitjEMUbRRRQAm0elBHHSiigBpPHQUqrkUUUuVWACvBoQcdKKKUQHUUUVQrs//9k="},5987:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaABoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Wf2YfgZ/w0p8bdE8E/8ACZeAvh9/bXnn+3vGmrf2Vodh5MEk/wDpFwVYJv8AK8tMqd0kiL3yP0U+Hv8Awb8/AjUvAthdeLv+CiH7Meh+JCrm8sdJ1XTtVsYsOdgS6m1G3eQFdpJa3TDOVwyqrH4r/wCCVo/42e/s4r/1VHwyee+NWtT+H+RX9rCR/L9env8A4dentX1eeY6tSrJRfQzjTXU/in/bm/YS/wCGJbnw7Gvxk+BXxcXxC12qn4c+K/7cbSvs/k/8fg8tPJ8zzv3Yy2fJlH8OT4DX63f8HmQ/42h+Bf8Asl2n9u39ravj/P8Ak/kjXt5XWnVw6nU3ZjPR2PUP2J/i/pf7PX7Znwj+IGtLcyaP4F8Z6P4hv0t1DTPb2l7DPIEBIDOUjbAJGTgZGc1/UYn/AAc8/sQ+V83xpaM8na3g/XsjA5GRZEE9emR/X+SfH3v92hVGeg/KuLNMBTxElUejNIyaPv8A/wCDkn/goF8Nf+CjH7fGi+LvhXqV9rXhnw74OtPDjX9xYy2a3U8d5fXDNHHKqyBNt0gyyqSQwxgAn8/Kcqjb0H5U2u/BU40qShEzqXbuf//Z"},2383:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAIUDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Gs7aBX1D+yt8Jvh7ffsUfE/x/wCKtP8ACd5rWgeJdK0jS38Qy62Lcxz6fqc7xRJpisfOaS1hIe42xDaQWGTXqPxJ/wCCRfgv4dyaldf8LI8calpfg621N/E8Nr4Mt21Lz7W20GdE0+L7dtuI2OvR73leEolrI+1shR+iyzKjCbpyvoc/I7XR8G5+v5UZzX6S+KP+CKngnQb/AML6HqXxB8RaXeap4yHw9tL6y8KC4l1TUrnXPENha3F3FLfqtvDHHouXEO5hu2hHYFz4X+0P/wAE6vC/7On7Pnh/xVqHxA1LWPEWraLp+oz6Lpmj284t5NR0qPU7Rg/2vzFtY0dop5ZY43D7GjjlQsyqGbUJNJPX0J5W1c+XbLS7c6at1dXDwxyytFGscXmEsqqzZ5GB8619kfsHaD+zr4l/ZY1Cz+Ll94b0/VrrXZ45riSZLbV4LfztGMBglG+ZN0Y1NAUgkhG52mK7Iw3x1fceE7H7v/H7c8jv+7t69n/Zg/YW1j9oH4c6v4tvNd0fw34esdP1+awE8wfUddu9K0p9Rlt7W2yDIAvkLI+4BBNkByNtbZhFOl78uXbVBD4j27TvgR+yGPAHgXUNW8YPb6p4qtIYdZtLDxNJKfDhnNgXuyjWhYyWxnv0+zuRvWyjyx3ebLl/G34d/sv6D8F/Eek+H7/TpPEUc+q3ugata+KZNQuZYIILf7AJ0NnGgN4N7NBu3QSF+YyfKj5vxN/wRq+OHhfV9PsLjTfDs1xeaoujzmLWEZdOvFuBbXMU7FQE+ySNF9okGY41mRtxUlh5F+yZ+yF48/bi+Ly+BPhpYabrniqa1lubawn1W3sXvkj/ANYITO6CRguW2KS21WbGFOPPpxpSXN7XYq7XQ86httMaJWlvLqOTbllW1DBT3wd/SotWsG0jUZrVmVmhcqWX7rDjBH1681o/EvwBqHwq+IGteGdWk06TU9BupLG7awvYr6282M7XCTRM0cgDAjcjEHB5NV/GRz4ovP8Af/oK9yMlKPNHYzM9Rvb5eaCpXj+tfZH/AAQZ+Gfwp+KP/BTL4c6f8XNc8M2Gg/bM22leJNFj1HR/FNw6NGmnzGRvLid2cNGZEdGdAvDFA3Tft7/s7fCfxF/wW01vwR8Kbeb4n+EfEXih4U8MfDrToNIit7hy4XSbGX5oNiMqCS4WNY4wZCAwTNefPMeTEOi46JXuVy6XPhDvS55r2r/goZ8A9J/Zk/a58WeCtD03xBpGm6P9lVbbWI5xLHM1rE1wIZJ4YJZ7UXBmEFw8MZmhEcm0bsV4pjLKPf8AOu2jWVWCqR2YnoAO4cUua9w/Z5+Gng3xh8GvGOoatbapdX2lW/mXEyRopskCvIptvn+Z/wB3kl9oIO3pknkfg78MdN8f2esyTrqNxFZyrEkkOIvssTRXEhuZVG4BQYY1Izt/eEbs7aftE2I89BzRTV6fzorQDrPh18ePHPwfsNSs/CXjTxb4VtdZULqEOjaxcWEd+ArKBKsTqJAFdwNwOA7DoTXSfBv9sv4j/A34n2vjDR/E19ea5YtNJDLqztqKpJNFHDJKFlJxI0UUUZcYYpGq5KgCvMaKw+rUm23FahdneePP2p/iR8S/HV14k1jxv4muNYutYfxAZotQkt0gv2nmuDcQxxlUhcS3Nw6mMLtM0hGNxznt8fvHj+ELPw63jjxg3h/T7SaxtdLbWrk2VtbTY82FId+xY5Nq7kACtgZBxXJ0jcCnHD0ltFfcPmZo3xz4Rsf+v25/9F29ejfCT9tbx78EvhLqvgvQ7rQ/7F1L+0QjX2iWl7d6ab+zFletaXEsbS2zT26rG5iYEhFPBGa8zs/EFxpVu0Mf2d4t5bZNbxzKDwMgOpwSMZx1wPSpR4suh/yx0v0/5Btv/wDEVVSnGatNXQtnc968Z/8ABVj43eOvFmsa9feKLBda8Q+HNT8K6te2+jWkM2pWeohBetIVj/10uxT5ow6kEqVJJPz7o+s3eg38N5Y3VxY3lqQ0U9vI0csLeqspyp9we5qz/wAJddf88dK/8Flv/wDEUf8ACXXX/PHSv/BZb/8AxFZ08LTh8CSHdvczW+5gdAMcCtLxgMeJ7z/rp/QUDxXdE/6nS+oH/INt/wD4iqd5cyXt3JNMzSSzHzHY9WY4JP61vbSwjtfgn+0BqXwJfVDp/h/wBr/9rLEsg8T+FbHXRB5e8jyftUb+UTvO4pjdhc52jC/GL9ofV/jPqumXlzovgnw1caTHIkJ8KeGbLw+sm8jJkFpHH5jDGAWyQCQOCa4WjFYfVKXP7S2vcd3sS3uoXGpztLdXE1zMwALyyF2IHTk5PFQl9uf8/wCf/r0tFbKKWi2EdBpPxOvtG0yO0j0/w7NHGMb59It5ZJO/zMy5b8c1i3+pS6lqFxcMscLXTs7rAgijG45Kqi4Cr6KBgdBUNGKOVAAGKKKKdgP/2Q=="},4601:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAcAIkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8G88UYwM19kf8E+v2WvA/xS+F/hHVPEfgPVPiJefED4pW3w7u1s9RubRvCNlLawyC/TyTgzyNPK0ZnDQgafMNrZYr0el/8Ei/COr6JpV8vxK8YRWtpBod54juZfBYktY7fVvD1/rVvJYSx3TefHEunyQzzzrBDEJllZxGjkfossypQm4Sv2OXlZ8JN1/Wtq90ez0PxElnNcNLLbXYgul8rbGNrYfDZJI4IzgZ696779sT9nrTf2Y/irqHhC1vPFN5f6PeXEF0+r6PBYRtGCr2zRNDczrIWhdWk2tsViNjyqQ58/8AH4z8Qtc2/wDQRuAP+/rCu2nWjUjzJ6EuLR+h3x2+G/7HfjL4o6eun6t4Rsmm1Ke1WLS9aGlWH2FTrU9vJKYUmiDSCLSYAzSo4SUmYRzOTFxHiL4Afsdwx+LLLQ/G1xqWp6BbkaLJfeKzZWvicySjzZZJvsDC2a1tlkdEVGM8u1cElYm808ff8El/id8PvD+tX1xrXw1vJvD8mqw3lhZeKYZLxbjS1gfUoQpCr5lrHcRNJlgoDnBJVgHXX/BI74sWN7er9s8CSaZYaEPET6yuvodMa2/tC507cJiuAv2q0mjMzgQY8tvN2Sxs/gxjRitKzNk2+hgf8FANG+CsPxN02++EV1Db6TftfxanZ2d095b27w3TxwXEIkSNo0nhCSCIltmThscDwg2ul/8AP9efUWg/+Lr6e1j/AIJCfEqdb6bwzqPhjxZY2Xh3StcFxa3Tx/bZr3w+dfextwynzJobFZJGJKqV8oghpkQ+LfFz9mvWPgz8fpPhvqms+ELjXrW9i066ubTWYm0yyuHYKY5rt9sUflscSMzBI8HLAA49TCYqly8kZX6mctXc4s2ulsP+P68/8Ax/8XTNV06Gxgt5IZmmiulLIzJsYYYqQRk9x6mvTv2xP2IPiN+wX8Q7Hwn8UNN0vQ/EmoWS6imn22r2uoTQwMxVHlFvI4i37SVDkFlG4DBBPm2q86BpLf7Ev/o0/wCNdlOpGpHng7okzhywA70ZyKlsIIbm/hjuZmtbeRgssyxeaYl7ttyM49M17X+1toHhLSNE8KtoNxoa3X2EGSLTLZAL5SFAnkZOBkqQAQSST0GTRKdnYDw3+nWnZrv/AIpfDHT/AAX4I0e+tY75Zrto1M00gaK/V7WGZpIgAAFWSQx8FugyQcivPwMVSlcBaM8V6N+yv4U0Hxv8XrDTdchurpZtz21skYME7ojSHzm3BggC9FB3E4JAqbxL8ONAf9pa48L6f/aUOlxajLayxyqqyRyRlg0UTAtuUsu1WIDYYZXPWfaK4Hmec0Vv/E/wzb+EvGMlnaw3NrGba3na3uDmW2eSFJHiY4ByrMV5APHIzWBVxd0BveC/iv4q+Gtlq1t4a8TeIfDtvr1sbLU4tL1Kazj1KA5zFOI2USpyflfI5PFdZ4t/bG+KnjK98JTXXj7xVb/8IDY2mneHEsdSls4tDjtbSKzia2SJlWGUwwoHkQB5DlmLMxJ81oxWUsPSlLmlFXA1/GvxK8SfEORX8QeINc15opLi4RtRv5bspJPIZJ3BkZsNJIS7kcsxJOTzSfEEbfiBrn8LLqVxx/21asduB/n0Nak3i68d9zrYSsQMvLYQSO3HdmQk/UkmrjTjFWSA9if/AIKR/F6fX9Q1T/hINNW/1TVNf1meUaJZ83WuJbpqMgHl4G9bWHauMRlTtCljXW6p/wAFivjlrHxWtfG02qeD/wDhJrCGaOyvR4R0zzLF5ru5vJZ4T5OUlee8uXZlI3eaVYMoVR83DxbdD/ljpf8A4LLb/wCIo/4S66/54aV/4LLb/wCIrmeBoPeCHzNHt1h/wU3+Llh4FvvDS6toUmj6ho+naNLBJoFm37uw046ZbTgmPi4WyKwmb77iKItlo0ZfG/ib8R9X+MHxE17xTr08N1rfiS+m1G/mjgSFJZ5XLyMEQBVBYnhQAM8Cqv8Awl11/wA8NK/8Flt/8RR/wl11/wA8dK/8Flv/APEVpTwtKHwRsIp6jqtxq1z511cT3U2xIvMmkMj7ERURctk7VRVUDoAoA4q5qvGgaSP9iX/0aaP+ErumGfJ0v/wW2/8A8RVfVNXm1UxtN5WI9yIscSxKgznhVAHUk1skkrIA0vUn0fUobqOK2mkhbcqXEKzRMf8AaRgVYfUGtTW/iJda9pclpJp/h63jkIJe10i3t5Rg54dFDD8DyMisOjFDimAEsyqCzYXoM9KKKKdgNXwx4yuPCS3At7XSLr7SVLG9sIropt3fdMinbncc4xnjOcCovEnii48VXUU01vptq8Q2/wChWcdqG75IQDJ9zzWfRilypgDMXbcx3H1PU0UUVWwH/9k="},3377:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAkAEEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8J7HSPtVsZ5Li3s4d/lq82/52wCQAqsTgEEnGBkc8jMn9jW3/AEGNN/74uP8A41Rc/wDIqWP/AF+XP/oFvUngnwTrXxL8Yab4e8N6RqniDX9YnW1sNM021e6vL6ZjhY4oowXdieiqCTX6s5W1Zxkf9jW3/QY03/vi4/8AjVH9jW3/AEGNN/74uP8A41XSfGb9nzxf+z94r0/RPFekx2OoatZR6hZLbX1vqEV5BI7xq8ctvJJG/wC8ikjIDEq8bqQGUgc2/hXVI7zUrdtN1BbjRVd9QiNs++wCOI3MwxmMK7KhLYwzAHkgUlUi1dMA/sa2/wCgxpv/AHxcf/GqP7Gtv+gxpv8A3xcf/GqtS/DfxFBbXU0nh/XEhsQzXMjWEoW3CojsXO3C4SSNjnGA6noRmeL4R+LJ7Ca6Twv4je1tryLT5pl0ycxxXMuDFAzbcCV9y7UPzNkYBzT513Azv7Gtv+gxpv8A3xcf/Gqh1HSjY28cyz291bzMyLJEWxuUKWUhgrDAZTnGDngnBw7UdAv9ItoZruxvLWG4aRInmgaNZWjba4UkYJVuGA6Hg4qS6/5FKy/6/Ln/ANF29O99UGxV8laKdRTAsXP/ACKlj/1+XP8A6Bb1+h//AATL/ap8I/sq/saw6Xrfxq0/wbqHxO8WNbz6ToFmYdT06xt/KuVuNXu/IvIJrGa5so7Nra5064lig1GaaEzQSahp91+e1tp9xrPhq3is4Zbqa3upnkjiUu6q6RBW2jnBKMM9ARzjIzF/wh+r/wDQJ1P/AMBZP8K5sTho14ckthxlY9d/ah/ae0r4u/ttaj478P6bNp/gXR9cij8JaMtulm2maFZzAWNt5SMyRy+QitIQzb55JZGZmdmP0b4Z/wCCnvwb+Gvx9+N3irTfAHjXxNY/tFapeReKjq11BZXmkaHqL6i2pWNn5LsksjG7s5Y5JsKsunxMUBClfhX/AIQ/V/8AoE6n/wCAsn+FH/CH6v8A9AnU/wDwFk/wqK2ApVIqE72Sa3to7XXz5Vf/AILCMuWTkt3b8L2+67P0L0n/AILkaB4E0LWLjQfAmqahrfiyxuJNbtdfkt7vSJ7qfTtD06ezaIANNp88Gl3Sybikuy9VFIaMzPB43/4LKeBvFXj/AEnX7Hw/8WPDdv4X8Sm+07QtM8SRR6bqunvrOm6mf7R3KWuLlFsPI9JBFYuXT7MVk/Pv/hD9X/6BOp/+Asn+FH/CH6v/ANAnU/8AwFk/wo+o0ufn1v6/18u13bdmTpxcXB7Nt/Nqzfz/AD+R7v8AtwftxWn7X/gzwLp8Phew8M3HhG+1+5lXT7WG0tLhNQvhcx7YogAJFUbXY/eODXg91/yKVl/1+XP/AKLt6X/hD9X/AOgTqf8A4Cyf4U/WLKbTPDllBcxSW8/2m4kMUi7ZApSABip5AJVgD0O0+hrajRhRpqnT2R0VKsqkueW5ToqPzqK2MyIrmk8sf5FFFSSHlj/Io8sf5FFFAB5Y/wAijyx/kUUUABQAf/Wo24FFFADqKKKm5R//2Q=="},9662:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaAB8DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8Gx83/wBavqD9kP8A4JI/Fj9sH4aTePreTwb8Ofhnb3Js38a+PNcj0HQ5JwWDJHLIC8pUo4YxRuqlGUkMCK8n/ZX/AGcm/ap+Oeh+AofGXgrwPeeIpvs1lqXiq7uLTTHmOBHE0sMMrRs5OFZ1CE4BYEgV9/f8HNvwquv2f/jb8NfhnY+NvBt14F+H/hGx0fw74K0a5uDd6IqQIbi9vYPJWCOW5mMhB86SZ0VHYAEY/RMXipurGhT0bOWMdLs+Kf22v2D/ABH+wt4t0PS9d8VfDXxlB4ksG1PTdR8G+JIdZtbi3DmPzCV2yIpcFVZ0UOVcKWKMB4i0fyn5d2Mcev8Anr+Br9F/+Dcn4F/s+fH79rnUdL+NXhvxR401C30jUNQs9PNhBJ4Z02zgtZJLm/1CT7QtwzDIjijjhdVkkRyScGP4y/auf4V3Xxz1yb4M/wDCZJ8PLqbztMtvFdtb2+pWKtljA5hnmSRUPCuWDsMblDAlqw2MvVdCW667IJR6nnIn/dEN/EPm9/15yR07Yz1r6B/Y/wDix8B7v4i+JL79p/w78WPHlvrEEKWeqeGtdhTUNPkVj5sskdyALliojVd0qKoWTKuWVo/niiu+rhFJ8jbv36kn3Z8Sf+CmHwj/AGd/2d/GHwx/ZN+HfjDwWPiRALDxT488Y6pFdeKL3T8hm0+3FrtitIXYESbCfMVyCAQpX4XSRVZdvuB7flUbdaKww+Fp0puMV/mB/9k="},7697:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAaAB4DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8LvBXhDVPiB4x0nQtDsbvVtZ1q8hsNPs7aMvNd3MrhIoowMlnZ2VQAMkkV+n/APwSe/4NpvHX7XnxP+IGj/HTRfiZ8HdL8I2sMdpcvpKwrql5K5JWGSZDFKiouWMW5fmT5vmyPj//AIJHfELx18J/+CjHwt1z4a+Abf4meN7LU3XTfD09u84ut9vLHLJ8pAUxQtJKJWIWLyt7EKhr9vf+DqT/AIKQ/H79huy+F+i/CnVtQ8E+GfFi3c2p+IrK1Vrie5iaMxWYmkVhEChMjBSHkwRuCqwb7fNMVWdZYelZN9TnhG6uz8h/+ChX/BE/4w/shftD/FTRfDvgH4geKPhv8PYjq6eLW0aX7E2lFPM85pwvlsUG8OFPBhkOMAkfFTJhR/D+P9e9f1Ufsc/ts/tEfG3/AIN7774rat4B/wCFk/GL+x76HTNLvtO8keLLUT+Ul29suzzgbcvIY4tn2gQ4QgyA1/LHfyyG/mLRfZ5N7b4lfyliOc7QOwBJAB6YPJ7b5Tj6lVulU1cewTj1R3n7If7Ufin9i39pTwf8TvB8yw+IPCN+l3bozMsV0hDJJBJsZS0csbSRuAcMjsK/ef8A4Je/8HNnhf8Abd8Z/ELw9+1FD8H/AAB4Vht7bUPDqXCSG3nAkKvb3D3DyRySLmJlIWPkOcHgD+dCIZkX/eFWQP3ee+xzn8RWmYYGlXdpLXv1JjNp2P22/wCCjv8AwdifELw58cvix8P/AIP6f4DvPh+bN9D8MeKrNp31KGVoVV7+KUP5LEOzmNDFhdsZJcqwb8RJp2uCS+99x3k7jkk57kH3PuTVeCRjAo3N+dOrfAYOnQj+7WvcUpNn/9k="},807:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/options-panel-100eeaf664f5256e33d53253fd3f0780.jpg"},7083:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/rippled-cli-61e766ae071eb06da7d98b00f6dbf2aa.jpg"},790:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/status-apps-343e3b5c827d40f01b2cd05e4cfb89ef.jpg"},7164:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/status-engine-e07c67aa823d448212466f9b45863a30.jpg"},5071:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAdCAYAAAC5UQwxAAAACXBIWXMAAA5NAAAOTQFG1WgJAAABxElEQVRIie2WP0vDQBjGn7YaLFnMDRak4NkOToJg9oL6GboGOpR+BCdRJz+COBS69iMoLWTv0tHBNIWi4JB0KcoV0SHcEZO79FqkOvhsL5e73/vn3veSy+cPP7FG5dcJ+wf+LpASBscOQQlTrutoQ+ejdn0Cxw4BAH5g4PRuH35gCFCvOQIlDK5notEti7WVgP2Wh1plJuz4gZQwPJ0/Ckeu7kvwAwOUMCU0M6VJWGdgwfVMYScdcT1TRKySEpiEAYBjhyK1ALBnzQFE0dWqMxExJUxZUyWw0S0rveSiVnQoJQzOcfgtvaqUpmrYrk9SkcV1cfYKPzBS0fKI/MDIdDaXnKWOHaJdnwj75LYibFWaOgMrgoUGrh92lDBAEiHfzCHj6SaqNweghEmj7wwsrfRzSWvID4nXQVaXZWGAJKUqxZs/Ccvqu6S0RlsWrN/y0GuOMi/aUsAsGK+pqr4yFXK50uUqMAAYvmzhaPcd1Jpju/iBWmWG4XMR41CdXiVwEQwApm8FuJ65FFQK1IGtCk3VkBKWGtiLrj6fLnyw87dTJmlb8InP3zdd8csDRBNKG8g36/bWMvu0G/+n9Hd/ov6BuvoCw/n+J9ZuJIUAAAAASUVORK5CYII="},5048:(e,A,t)=>{t.d(A,{Z:()=>a});const a="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAYABkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8K/DHhbUPGviLT9I0mzudS1XVrqOys7O1iaae5mkYJHGiKCWZmIAUAkk8Cvqq+/4JYaL8O7ybw78R/wBpD4G/Dv4jLFufwte3Go6g+mShSXt7+8s7SW1tplJjGwSyEMWBwyMtH/BD/wA+H9v7S5NLghn8Yf8ACMeJf+EOE0iIo13+xL37AVD8NL5+wRqPm8xlK/Mormf2f/Bt9rP7Cf7UGt3nijU9JuNBm8MLdaSUh/4ncs2pyofPaVDODEQz7I2QFsl87Qtfo1WtUlU9nF8vmcZ5j+05+yr4y/ZF+Jn/AAi3jWxtra8ms4dU0+8sruO+0/WbCbJgvrS5iLRz28gGVkU4yCpwyso8++yt6f8Ajy/419e/tPx3w/4JC/syt4s3tr03iTxWfC/mOS6eHAbABWU8iP7eb0w5yCBNtbOVHyDmT0t//HP8K3wuIc46gXPCnizU/AviOw1nRdQvNK1jSrhLuyvLSVoZ7WVGDI6OpDKysAQQcg9K+ttf/wCCs+i/FS/fxD8Sf2afgP8AED4hYMreJp7XUNLfU7kn5ri+tbK6ht7l2G0HCR5I3Z3EmiirqYanVfvoDwH9qT9rHxt+2N8U28XeOtQtr7UY7OLTLK3s7KGxsdKsIQVhsraCJVSGCNThUUcZYnLMWPnv2x/Vf++BRRXTQpRhDligP//Z"},1412:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/status-system-1715f704ad5a3f3165dc7e7e773c8866.jpg"},6200:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-logs-c20f46f158e4377b6c454e5fda904dfc.jpg"},6490:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-table-54cab2d0f20f4901b7e9b26ff758d874.jpg"},1623:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-tabs-06a0e891c3cb1b948ec163e6e59ff07a.jpg"},7317:(e,A,t)=>{t.d(A,{Z:()=>a});const a=t.p+"assets/images/workloads-screen-76d388775052a81d40c476b5de7d90de.jpg"}}]); \ No newline at end of file diff --git a/es/assets/js/4c80fdcb.270f98c5.js b/es/assets/js/4c80fdcb.270f98c5.js new file mode 100644 index 000000000000..951c9fc7a578 --- /dev/null +++ b/es/assets/js/4c80fdcb.270f98c5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8511],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>g});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={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,o=e.mdxType,a=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(r),f=o,g=p["".concat(c,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(g,i(i({ref:t},u),{},{components:r})):n.createElement(g,i({ref:t},u))}));function g(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4155:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={},i="Ethereal Engine",l={unversionedId:"creator/tutorials/ethereal_engine/readme",id:"creator/tutorials/ethereal_engine/readme",title:"Ethereal Engine",description:"In this section you will various tutorials for Ethereal Engine.",source:"@site/docs/2_creator/5_tutorials/1_ethereal_engine/readme.md",sourceDirName:"2_creator/5_tutorials/1_ethereal_engine",slug:"/creator/tutorials/ethereal_engine/",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/1_ethereal_engine/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Tutorials",permalink:"/etherealengine-docs/es/docs/creator/tutorials/"},next:{title:"Unity Bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge"}},c={},s=[],u={toc:s},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-engine"},"Ethereal Engine"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/530a89a7.4439efde.js b/es/assets/js/530a89a7.4439efde.js new file mode 100644 index 000000000000..2c9c24fb637c --- /dev/null +++ b/es/assets/js/530a89a7.4439efde.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5111],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>g});var n=r(7294);function o(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 a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={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,o=e.mdxType,i=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),f=o,g=p["".concat(l,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(g,a(a({ref:t},u),{},{components:r})):n.createElement(g,a({ref:t},u))}));function g(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},1869:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const i={hide_table_of_contents:!0},a="Unity Bridge",c={unversionedId:"creator/tutorials/ethereal_engine/unity_bridge",id:"creator/tutorials/ethereal_engine/unity_bridge",title:"Unity Bridge",description:"",source:"@site/docs/2_creator/5_tutorials/1_ethereal_engine/01_unity_bridge.md",sourceDirName:"2_creator/5_tutorials/1_ethereal_engine",slug:"/creator/tutorials/ethereal_engine/unity_bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/1_ethereal_engine/01_unity_bridge.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/"},next:{title:"Unreal Bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge"}},l={},s=[],u={toc:s},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"unity-bridge"},"Unity Bridge"),(0,o.kt)("iframe",{width:"100%",height:"600",src:"https://www.youtube.com/embed/uNnCZ_T-qo0?list=PLE345Qm2tFnXRkHLKf1Hz3FRNUdt14vJK&showinfo=0&rel=0",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/54e37525.76419b03.js b/es/assets/js/54e37525.76419b03.js new file mode 100644 index 000000000000..b4043f515877 --- /dev/null +++ b/es/assets/js/54e37525.76419b03.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6718],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||r;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c<r;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5888:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var o=n(7462),a=(n(7294),n(3905));const r={hide_table_of_contents:!0},i="Writing Reasonable & Testable Code",s={unversionedId:"creator/testing/reasonable_code",id:"creator/testing/reasonable_code",title:"Writing Reasonable & Testable Code",description:"Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application.",source:"@site/docs/2_creator/6_testing/2_reasonable_code.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/reasonable_code",permalink:"/etherealengine-docs/es/docs/creator/testing/reasonable_code",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/2_reasonable_code.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Testing Basics",permalink:"/etherealengine-docs/es/docs/creator/testing/testing_intro"},next:{title:"Writing Good Tests",permalink:"/etherealengine-docs/es/docs/creator/testing/test_driven_development"}},l={},c=[{value:"Example",id:"example",level:3},{value:"Code Composition / Decomposition",id:"code-composition--decomposition",level:2},{value:"Example",id:"example-1",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"writing-reasonable--testable-code"},"Writing Reasonable & Testable Code"),(0,a.kt)("p",null,"Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application."),(0,a.kt)("p",null,"In the functional programming (FP) paradigm, pure functions are functions which do not mutate any existing state of ",(0,a.kt)("em",{parentName:"p"},"any")," scope. Since we are not in a fully functional paradigm, a focus on these qualities of functions can be priceless: stateless functions with ",(0,a.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Referential_transparency"},"referential transparency"),"."),(0,a.kt)("p",null,"Stateless means that the function itself has ",(0,a.kt)("strong",{parentName:"p"},"no memory of the past"),". Referential transparency means that the function is only operating on the parameters, and ",(0,a.kt)("strong",{parentName:"p"},"nothing else")," (no global state access, etc)."),(0,a.kt)("p",null,"These types of functions may (arguably) mutate parameter state, but may only operate on the given parameters. State residing outside of the scope of a stateless function should ",(0,a.kt)("strong",{parentName:"p"},"never be depended on or mutated"),". This will ensure that the function holds no inherent state of its own, and therefore will exhibit the behavior of being referentially transparent and ",(0,a.kt)("strong",{parentName:"p"},"idempotent"),". "),(0,a.kt)("p",null,"Idempotency is a quality of any function which can be executed several times without changing the output for a specific input. Idempotent functions can be thought of as mappings from one input to one output. "),(0,a.kt)("p",null,"All of this combined makes functions extremely simple to reason about, very reusable, and easy to test! Three gulls, one scone."),(0,a.kt)("h3",{id:"example"},"Example"),(0,a.kt)("p",null,"Here is an example of a function that does not exhibit referential transparency, nor is it stateless:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"let y = 3\nconst someFunction = x => {\n x += y\n y++\n return x\n}\n\nsomeFunction(3) // => 6\nsomeFunction(3) // => 7\nsomeFunction(3) // => 8\n")),(0,a.kt)("p",null,"This function is also not idempotent. Same input, different output! Not good for reasonable code, difficult to predict."),(0,a.kt)("p",null,"Written as a stateless, idempotent function with referential transparency:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const someFunction = (data, x) => {\n x += data.y\n data.y++\n return x\n}\n\nsomeFunction({ y: 3 }, 3) // => 6\nsomeFunction({ y: 3 }, 3) // => 6\nsomeFunction({ y: 3 }, 3) // => 6\n")),(0,a.kt)("p",null,"The newly written function now holds no inherent state of its own and does not operate on any data that was not passed into the function as explicit arguments. It is also idempotent: same input, same output! Very reasonable and easy to predict."),(0,a.kt)("h2",{id:"code-composition--decomposition"},"Code Composition / Decomposition"),(0,a.kt)("p",null,"We must now capture the process of decomposing a program into smaller pieces that are more reusable, more reliable, and easier to understand. Then we can combine each individual piece to form an entire program that is easier to reason about as a whole. FP tends to follow this fundamental principle."),(0,a.kt)("p",null,"FP falls under the umbrella of declarative programming paradigms: it expresses a set of operations without revealing how they\u2019re implemented or how data flows through them. Unlike imperative programming, declarative programming separates program description from evaluation. It focuses on the use of expressions to describe what the logic of a program is without necessarily specifying its control flow or state change."),(0,a.kt)("p",null,"These two paradigms can be utilized to form powerful and extremely testable functions and compositions which support a sturdy codebase. Write functions imperatively, then compose them together declaratively!"),(0,a.kt)("h3",{id:"example-1"},"Example"),(0,a.kt)("p",null,"Using the previous unit/integration test examples, lets see what the algorithm would look like if written imperatively:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const algorithm = x => {\n // first, add two\n x += 2\n // then, multiply by three\n x *= 3\n // finally, divide by two\n x /= 2\n return x\n}\n")),(0,a.kt)("p",null,"Rewritten declaratively, as demostrated before but with a newly introduced ",(0,a.kt)("inlineCode",{parentName:"p"},"pipe")," function (a standard function in FP):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const addTwo = x => x + 2\nconst multThree = x => x * 3\nconst halve = x => x / 2\n\nconst algorithm = pipe(addTwo, multThree, halve)\n\nalgorithm(4) // => 9\n")),(0,a.kt)("p",null,"As you can see, the imperative function has no reusable parts, but the declarative version does! This is a simple example, but in larger-scale functions and systems this simple distinction can be a powerful tool in writing reasonable, testable, and reusable code. Bonus: the code is ",(0,a.kt)("em",{parentName:"p"},"self documenting"),". No need for comments here. Just pure, self-descriptive functions!"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/58222842.4c3c6afe.js b/es/assets/js/58222842.4c3c6afe.js new file mode 100644 index 000000000000..a9826786fe8d --- /dev/null +++ b/es/assets/js/58222842.4c3c6afe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8718],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=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=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=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"]),c=d(n),p=i,m=c["".concat(s,".").concat(p)]||c[p]||h[p]||o;return n?a.createElement(m,l(l({ref:t},u),{},{components:n})):a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,l=new Array(o);l[0]=p;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[c]="string"==typeof e?e:i,l[1]=r;for(var d=2;d<o;d++)l[d]=n[d];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}p.displayName="MDXCreateElement"},765:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const o={},l="Ethereal Engine on AWS",r={unversionedId:"host/devops_deployment/AWS_setup",id:"host/devops_deployment/AWS_setup",title:"Ethereal Engine on AWS",description:"The value RELEASE_NAME referenced throughout this guide is the name of the deployment, e.g. dev or prod.",source:"@site/docs/1_host/2_devops_deployment/2_AWS_setup.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/AWS_setup",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/2_AWS_setup.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on Minikube",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/minikube"},next:{title:"Installing Projects",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects"}},s={},d=[{value:"Ways of serving client files in production",id:"ways-of-serving-client-files-in-production",level:2},{value:"Serve client files from client pods",id:"serve-client-files-from-client-pods",level:3},{value:"Serve client files from API pods",id:"serve-client-files-from-api-pods",level:3},{value:"Serve client files from Storage Provider (S3 + Cloudfront)",id:"serve-client-files-from-storage-provider-s3--cloudfront",level:3},{value:"Create EKS cluster with four nodegroups",id:"create-eks-cluster-with-four-nodegroups",level:2},{value:"Enable EBS CSI Addon (if EKS version is 1.23 or later)",id:"enable-ebs-csi-addon-if-eks-version-is-123-or-later",level:4},{value:"Install Cluster Autoscaler (optional)",id:"install-cluster-autoscaler-optional",level:4},{value:"Create launch template",id:"create-launch-template",level:4},{value:"Create nodegroup for instanceservers",id:"create-nodegroup-for-instanceservers",level:4},{value:"Create nodegroup for redis",id:"create-nodegroup-for-redis",level:4},{value:"Create nodegroup for builder",id:"create-nodegroup-for-builder",level:4},{value:"Create ECR repositories for built images.",id:"create-ecr-repositories-for-built-images",level:2},{value:"Create IAM Roles for S3/SES/SNS (or a single admin role)",id:"create-iam-roles-for-s3sessns-or-a-single-admin-role",level:2},{value:"Creating an IAM role",id:"creating-an-iam-role",level:3},{value:"IAM Roles to create",id:"iam-roles-to-create",level:3},{value:"Creating new credentials for an IAM user",id:"creating-new-credentials-for-an-iam-user",level:3},{value:"Create RDS box",id:"create-rds-box",level:2},{value:"Accessing RDS box from an external machine",id:"accessing-rds-box-from-an-external-machine",level:3},{value:"Create RDS instance",id:"create-rds-instance",level:3},{value:"Edit security group to allow instanceserver traffic into VPC",id:"edit-security-group-to-allow-instanceserver-traffic-into-vpc",level:2},{value:"Create Route 53 Hosted Zone and set up ACM certificates",id:"create-route-53-hosted-zone-and-set-up-acm-certificates",level:2},{value:"Purchase and register domain through Route53 (optional)",id:"purchase-and-register-domain-through-route53-optional",level:3},{value:"Create Route 53 Hosted Zone",id:"create-route-53-hosted-zone",level:3},{value:"Point external registrar subdomains to use Route53 Nameservers (only if your domain is registered outside Route53)",id:"point-external-registrar-subdomains-to-use-route53-nameservers-only-if-your-domain-is-registered-outside-route53",level:4},{value:"Create certificates with ACM",id:"create-certificates-with-acm",level:3},{value:"If you are serving client files from client or API pods",id:"if-you-are-serving-client-files-from-client-or-api-pods",level:4},{value:"If you are serving client files from the Storage Provider",id:"if-you-are-serving-client-files-from-the-storage-provider",level:4},{value:"Install Agones, ingress-nginx, and a copy of redis for each deployment",id:"install-agones-ingress-nginx-and-a-copy-of-redis-for-each-deployment",level:2},{value:"Install Agones",id:"install-agones",level:3},{value:"Install redis for each deployment",id:"install-redis-for-each-deployment",level:3},{value:"Installing redis as part of Ethereal Engine chart (not recommended for production)",id:"installing-redis-as-part-of-ethereal-engine-chart-not-recommended-for-production",level:4},{value:"Install ingress-nginx",id:"install-ingress-nginx",level:3},{value:"Set up Simple Email Service (optional)",id:"set-up-simple-email-service-optional",level:2},{value:"Create SMTP credentials",id:"create-smtp-credentials",level:3},{value:"Move SES out of Sandbox",id:"move-ses-out-of-sandbox",level:3},{value:"Verifying test emails",id:"verifying-test-emails",level:4},{value:"Set up Simple Notification Service (optional)",id:"set-up-simple-notification-service-optional",level:2},{value:"Set up S3 bucket for static resources and Cloudfront distribution",id:"set-up-s3-bucket-for-static-resources-and-cloudfront-distribution",level:2},{value:"Create S3 bucket",id:"create-s3-bucket",level:3},{value:"Create Cloudfront distribution",id:"create-cloudfront-distribution",level:3},{value:"Legacy cache settings",id:"legacy-cache-settings",level:4},{value:"Set up DNS records",id:"set-up-dns-records",level:2},{value:"Create GitHub fork of Ethereal Engine repository.",id:"create-github-fork-of-ethereal-engine-repository",level:2},{value:"Grant EKSUser access to cluster",id:"grant-eksuser-access-to-cluster",level:2},{value:"Deploy to EKS using Helm",id:"deploy-to-eks-using-helm",level:2},{value:"Fill in Helm config file with variables",id:"fill-in-helm-config-file-with-variables",level:3},{value:"Configuration variables of note",id:"configuration-variables-of-note",level:3},{value:"<api/instanceserver/taskserver>.extraEnv.AUTH_SECRET",id:"apiinstanceservertaskserverextraenvauth_secret",level:4},{value:"<api/client/taskserver>.affinity.nodeAffinity",id:"apiclienttaskserveraffinitynodeaffinity",level:4},{value:"builder.extraEnv.PRIVATE_ECR",id:"builderextraenvprivate_ecr",level:4},{value:"(everything).image.repository",id:"everythingimagerepository",level:4},{value:"GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET",id:"github_client_idgithub_client_secret",level:4},{value:"Run Helm install",id:"run-helm-install",level:3},{value:"Kick off GitHub Actions",id:"kick-off-github-actions",level:2},{value:"Overview of the build process",id:"overview-of-the-build-process",level:3},{value:"Install Elastic Search and Kibana using Helm for Server Logs",id:"install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Upgrading an existing Helm deployment",id:"upgrading-an-existing-helm-deployment",level:3}],u={toc:d},c="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(c,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"ethereal-engine-on-aws"},"Ethereal Engine on AWS"),(0,i.kt)("p",null,"The value ",(0,i.kt)("inlineCode",{parentName:"p"},"RELEASE_NAME")," referenced throughout this guide is the name of the deployment, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"dev")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"prod"),"."),(0,i.kt)("h2",{id:"ways-of-serving-client-files-in-production"},"Ways of serving client files in production"),(0,i.kt)("p",null,"There are multiple ways to serve built client files in a production environment.\nYou should decide how you want to serve them now, because a few later steps will be affected\nby that choice, and changing your AWS configuration after everything has been set up one way\nis a little tricky:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"From client pods (separate from API pods)"),(0,i.kt)("li",{parentName:"ul"},"From API pods"),(0,i.kt)("li",{parentName:"ul"},"From the storage provider, such as S3/Cloudfront")),(0,i.kt)("h3",{id:"serve-client-files-from-client-pods"},"Serve client files from client pods"),(0,i.kt)("p",null,"This is the default method. The Helm charts assume that the deployment will have client pods\nto serve client files, and the client ingress will point traffic to the client pods. The client\nURL will be pointed to the EKS Load Balancer, and you will not need a separate client certificate."),(0,i.kt)("p",null,"This option gives you slightly more flexibility in scaling a deployed cluster than serving\nfrom the API pods, since you can scale the number of API and client pods independently."),(0,i.kt)("p",null,"Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture\nof how projects are built and served, and serving from the Storage Provider may end up being the only\nallowable option."),(0,i.kt)("h3",{id:"serve-client-files-from-api-pods"},"Serve client files from API pods"),(0,i.kt)("p",null,"This will make your builder build and serve the client service from the API pods. The Helm\nchart will not have a client deployment, serviceaccount, configmap, etc., and the client\ningress will point to the API pods. The client URL will be pointed to the EKS Load Balancer,\nand you will not need a separate client certificate."),(0,i.kt)("p",null,"To enable this, set client.serveFromApi to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," in your Helm config file when you are configuring it.\nThis needs to be applied to both the builder deployment and the main deployment, but if you set this\nbefore deploying anything, it will be applied to both."),(0,i.kt)("p",null,"This option can save you some money by requiring fewer nodes in order to host all of the\nAPI+client pods you desire, as you do not need capacity for separate client pods. It offers\nslightly less flexibility in scaling since you cannot scale the number of API and client pods\nseparately; more client capacity would require more API capacity, and vice versa. It also\nwill result in slightly longer deployment times, as the combined API+client Docker images\nare larger than an API-only or client-only image (though smaller than the sum of the two\nseparate images), which will mean a few more seconds to download to each node."),(0,i.kt)("p",null,"Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture\nof how projects are built and served, and serving from the Storage Provider may end up being the only\nallowable option."),(0,i.kt)("h3",{id:"serve-client-files-from-storage-provider-s3--cloudfront"},"Serve client files from Storage Provider (S3 + Cloudfront)"),(0,i.kt)("p",null,"This will make the client build process push all of its built files to S3 and serve them via\nCloudfront. Static resources will also be served from the client domain instead of a separate\nresources domain. The client URL will be pointed to the Cloudfront distribution, not the EKS Load\nBalancer; only API and instanceserver traffic will go to the EKS cluster. You will need a separate\nclient certificate, but you will not need a resources domain certificate."),(0,i.kt)("p",null,"As of this writing, only Amazon S3/Cloudfront is supported as a storage provider\nin a cloud environment."),(0,i.kt)("p",null,"To enable this, set builder.extraEnv.SERVE_CLIENT_FROM_STORAGE_PROVIDER to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," in the\nHelm config file when you are configuring it. Also make sure that builder.extraEnv.STORAGE_PROVIDER is set to ",(0,i.kt)("inlineCode",{parentName:"p"},"s3"),"."),(0,i.kt)("p",null,"This option can greatly speed up the time it takes for users to fully load your worlds,\nsince every client file can be served from a CDN close to them, rather than\nhaving to fetch them all from the closest physical server. It will also slightly speed up build times and deployment\ntimes since the client build does not need to be pushed to a Docker repo (though a cache of the build will still\nbe pushed to speed up future builds)."),(0,i.kt)("h2",{id:"create-eks-cluster-with-four-nodegroups"},"Create EKS cluster with four nodegroups"),(0,i.kt)("p",null,"You first need to set up an EKS cluster for Ethereal Engine to run on.\nWhile this can be done via AWS' web interface, the ",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl")," CLI\nwill automatically provision more of the services you need automatically,\nand is thus recommended."),(0,i.kt)("p",null,"First, follow ",(0,i.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html"},"these instructions"),"\nfor setting up aws-cli, eksctl, and configuring aws-cli with your AWS credentials.\nYou should also set up kubectl and Helm, as we will be using that to install multiple codebases from Charts."),(0,i.kt)("p",null,"Next run the following command:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"eksctl create cluster --name <name> --version <version> --region <region> --managed --nodegroup-name <name> --node-type <instance type> --nodes <target_node_number> --nodes-min <minimum_node_number> --nodes-max <maximum_node_number> --spot")),(0,i.kt)("p",null,"This will create an EKS cluster with a managed nodegroup in the specified region, including automatically\ncreating subnets, making a VPC, and more. It may take up to 15 minutes to complete."),(0,i.kt)("p",null,"You can also use the flag ",(0,i.kt)("inlineCode",{parentName:"p"},"--zones <zone1>,<zone2>")," to specify which Availability Zones the cluster\nshould set up in. Some regions have zones that are unavailable, but which eksctl will try to\nuse if --zones is not specified, leading to the setup to fail. As an example, us-west-1 (as of this\nwriting) does not have any resources available in us-west-1b; if you are setting up in us-west-1,\nyou would want to use ",(0,i.kt)("inlineCode",{parentName:"p"},"--zones us-west-1a,us-west-1c"),"."),(0,i.kt)("p",null,"Note that the region matters for almost all services in AWS. The default region is 'us-east-1',\nbut if you make the cluster in any other region, you'll need to make sure you're creating certs,\nDNS records, etc. in the same region."),(0,i.kt)("p",null,"As of this writing, the API and client are configured to run on a nodegroup named 'ng-1'.\nIf you name it something else, be sure to change the NodeAffinity in the configuration file. This is one of ",(0,i.kt)("strong",{parentName:"p"},"four"),"\nnodegroups that will be created for various services to run on."),(0,i.kt)("p",null,"Make sure to increase the maximum node limit, as by default target, minimum, and maximum are\nset to 2, and Ethereal Engine's setup will definitely need more than two nodes if you've configured\nthem to use relatively small instance types such as t3a.medium."),(0,i.kt)("h4",{id:"enable-ebs-csi-addon-if-eks-version-is-123-or-later"},"Enable EBS CSI Addon (if EKS version is 1.23 or later)"),(0,i.kt)("p",null,"Follow the instructions ",(0,i.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/eks/latest/userguide/managing-ebs-csi.html"},"here"),"\nto enable an EKS addon that's required for any cluster that will have Persistent Volumes, which an\nEthereal Engine deployment cluster will."),(0,i.kt)("h4",{id:"install-cluster-autoscaler-optional"},"Install Cluster Autoscaler (optional)"),(0,i.kt)("p",null,"While not necessary, it can be useful to have an autoscaler installed in the cluster to increase\nthe number of nodes available for pods when the cluster has high traffic and to decrease that\nnumber when it has low traffic."),(0,i.kt)("p",null,"Follow ",(0,i.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/eks/latest/userguide/autoscaling.html#cluster-autoscaler"},"these instructions"),"\nto set up the autoscaler. Any managed nodegroups created in the following steps should by default be\ntagged such that the autoscaler can control them, so no further action should be required."),(0,i.kt)("p",null,"Note that there is some lag time on scaling up and down. It generally takes about 5 minutes from\nthe time that the autoscaler sees the need to add more nodes before those nodes have been spun up,\nthe appropriate Docker image has been installed onto them, and they are ready to be used. It takes about\n15 minutes for the autoscaler to actually remove nodes that are deemed superfluous, as a hedge against\nthe recent high traffic picking up again."),(0,i.kt)("p",null,"The OIDC provider that was created in the prior step, installing the EBS CSI Addon, can be re-used in this step."),(0,i.kt)("h4",{id:"create-launch-template"},"Create launch template"),(0,i.kt)("p",null,"Go to EC2 -> Launch Templates and make a new one. Name it something like 'etherealengine-production-instanceserver'.\nMost settings can be left as-is, except for the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Storage -> Add a volume, set the size to ~20GB, and for Device name select '/dev/xvda'."),(0,i.kt)("li",{parentName:"ul"},"Network Interfaces -> Add one, and under 'Auto-assign public IP' select 'Enable'")),(0,i.kt)("h4",{id:"create-nodegroup-for-instanceservers"},"Create nodegroup for instanceservers"),(0,i.kt)("p",null,"Go to the AWS website, then go to EKS -> Clusters -> click on the cluster you just made -> Configuration -> Compute.\nYou should see one managed nodegroup already there; clicking on its name will open up information\nand editing, though you can't change the instance type after it's been made."),(0,i.kt)("p",null,"Back at the Compute tab, click on Add Node Group. Pick a name (something like ng-instanceservers-1 is recommended),\nselect the IAM role that was created with the cluster (it should be something like ",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>"),"),\ntoggle the Use Launch Template toggle and select the launch template you made in the previous step,\nthen click Next. On the second page, Choose the instance type(s) you'd like for the group,\nset the minimum/maximum/desired scaling sizes, and hit Next (t3(a).smalls are recommended).\nThere may be connection issues with instanceserver instances in private subnets, so remove all of the private\nsubnets from the list of subnets to use, and make sure that public subnets are being used (sometimes\nthe workflow only selects private subnets by default). Hit Next, review everything, and click Create."),(0,i.kt)("h4",{id:"create-nodegroup-for-redis"},"Create nodegroup for redis"),(0,i.kt)("p",null,"Redis should get its own nodegroup to isolate it from any other changes that might be made to your cluster.\nAs with the instanceserver nodegroup, it's not strictly necessary, but can prevent various other things from\ngoing down due to the redis servers getting interrupted."),(0,i.kt)("p",null,"Back at the Compute tab, click on Add Node Group. Pick a name (the default config in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.minikube.template.values.yaml"},"ethereal-engine-ops")," assumes\na name of 'ng-redis-1'), select the IAM role that was created with the cluster\n(it should be something like ",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>"),"),\ntoggle the Use Launch Template toggle and select the launch template used to make the initial nodegroup,\nthen click Next. On the second page, Choose the instance type(s) you'd like for the group,\nset the minimum/maximum/desired scaling sizes (you can probably get away with a single t3(a).small, but it's recommended\nto have at least two nodes so that one going down doesn't kill the entire deployment from a lack of redis), and hit Next.\nThe default subnets should be fine, so hit Next, review everything, and click Create."),(0,i.kt)("h4",{id:"create-nodegroup-for-builder"},"Create nodegroup for builder"),(0,i.kt)("p",null,"The full Ethereal Engine stack needs a builder server within the cluster in order to bundle and build\nEthereal Engine projects into the codebase that will be deployed. This should run on its own nodegroup\nthat has a single node - only one copy of the builder should ever be running at a time, and\ndue to the high memory needs of building the client service, a box with >8 GB of RAM is needed."),(0,i.kt)("p",null,"Back at the Compute tab, click on Add Node Group. Pick a name (something like ",(0,i.kt)("inlineCode",{parentName:"p"},"ng-dev-builder-1")," is recommended) and\nselect the IAM role that was created with the cluster (it should be something like\n",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>"),"). You don't need to use any Launch Template\nfor this nodegroup. Click Next."),(0,i.kt)("p",null,"On the second page, you can change the Capacity Type to ",(0,i.kt)("inlineCode",{parentName:"p"},"Spot")," if you want to in order to save money; the builder\nservice will likely not be running very often or for too long, so the odds of it getting interrupted by Spot instance\noutages are low, and it can always re-build if that does happen. Set the Disk Size to 50 GB; it takes a good deal of\ndisk space to install and build the Ethereal Engine codebase, and the default 20 GB will almost certainly not be enough."),(0,i.kt)("p",null,"For Instance Types, you need to only select types that have more than 8 GB; t3a.xlarge are the cheapest that fit\nthis criteria. If you were to pick something with 8GB, it's highly likely that most builds would crash the node,\nas Kubernetes tends to restart nodes if they get anywhere near memory capacity.\nUnder Node Group Scaling Configuration, set all three ",(0,i.kt)("inlineCode",{parentName:"p"},"nodes")," values to 1. We only want a single copy of the builder\nat any given time, and running multiple powerful boxes can get pricey. Click Next."),(0,i.kt)("p",null,"You can leave the subnets on the next page alone and click Next. On the last page, click Create."),(0,i.kt)("h2",{id:"create-ecr-repositories-for-built-images"},"Create ECR repositories for built images."),(0,i.kt)("p",null,"The Ethereal Engine deployment process will be building multiple Docker images, and those need to be stored somewhere.\nIn AWS, that somewhere is ",(0,i.kt)("a",{parentName:"p",href:"https://us-west-1.console.aws.amazon.com/ecr/get-started"},"Elastic Container Registry"),".\nYou need to make those repositories in the same AWS region where the EKS cluster is running."),(0,i.kt)("p",null,"Go to the ECR link above and click Get Started under Create a Repository. If you're very concerned about any of your\nEthereal Engine project codebase(s) getting out, you can choose Private for Visibility Settings, but normally Public is fine.\nYou'll be needing to create multiple repositories for each deployment, e.g. several repos for a ",(0,i.kt)("inlineCode",{parentName:"p"},"dev")," deployment,\nseveral more for a ",(0,i.kt)("inlineCode",{parentName:"p"},"prod")," deployment, etc."),(0,i.kt)("p",null,"Assuming you're first doing a ",(0,i.kt)("inlineCode",{parentName:"p"},"dev")," deployment, name the first repo ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-<RELEASE_NAME>-builder")," under Repository\nName, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-builder"),". You shouldn't need to change any other settings, though if you're using a Private\nrepo and want to turn on Tag Immutability, that's fine. The image tags that are generated should never collide, but it\nwill prevent any manual overwriting of a tag. Click Create Repository."),(0,i.kt)("p",null,"You will need to make four more repos for each of the services that are deployed as part of the Ethereal Engine stack -\n",(0,i.kt)("inlineCode",{parentName:"p"},"api"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"client"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"instanceserver")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"taskserver"),", which are also in the form ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-<RELEASE_NAME>-<service_name>"),".\ne.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-api"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-client"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-instanceserver")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-dev-taskserver"),".\nEverything else can be left alone for those, too."),(0,i.kt)("p",null,"On the ",(0,i.kt)("a",{parentName:"p",href:"https://us-west-1.console.aws.amazon.com/ecr/repositories"},"repositories page"),", you should see both of\nthe repositories you made. If you don't see any, you may be on the wrong tab up top - click Private or Public to switch\nbetween them. Also check that you're in the right AWS region. You'll see a column 'URI'. If you made public repos,\nthe URIs should be in the form ",(0,i.kt)("inlineCode",{parentName:"p"},"public.ecr.aws/<identifier>/etherealengine-<RELEASE_NAME>(-builder)"),"; if you made private\nrepos, the URIs should be in the form ",(0,i.kt)("inlineCode",{parentName:"p"},"<AWS_account_id>.dkr.ecr.<AWS_region>.amazonaws.com/etherealengine-<deployment>(-builder)"),".\nTake note of everything before the ",(0,i.kt)("inlineCode",{parentName:"p"},"/etherealengine-<RELEASE_NAME>")," - you'll need to add that as a variable in later steps.\nIt will be called ",(0,i.kt)("inlineCode",{parentName:"p"},"ECR_URL")," there."),(0,i.kt)("h2",{id:"create-iam-roles-for-s3sessns-or-a-single-admin-role"},"Create IAM Roles for S3/SES/SNS (or a single admin role)"),(0,i.kt)("p",null,"Ethereal Engine interfaces with several AWS services and requires credentials for these purposes. You could make\none admin role with full access to all AWS services, but we recommend making separate, scoped roles for\neach individual service. To create a role, do the following:"),(0,i.kt)("h3",{id:"creating-an-iam-role"},"Creating an IAM role"),(0,i.kt)("p",null,"Go to IAM->Users, and click on the Add User button. For User Name, enter ",(0,i.kt)("inlineCode",{parentName:"p"},"<service>-admin"),", e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"S3-admin"),".\nCheck the box for Programmatic Access, the click on the Next:Permissions button.\nClick on 'Attach existing policies directly'. In the Filter Policies text box, you'll want to\nenter the name of the service to narrow down the policy list significantly. Then, look for the FullAccess\npolicy for that service and select that, and click the Next:Tags button. You don't need to tag it with\nanything, just click the Next:Review button, then the Create User button."),(0,i.kt)("p",null,"The following screen should show Success and have the user listed. Copy the 'Access key ID' somewhere, and\nalso click the Show toggle under 'Secret access key' and copy that elsewhere as well. You will put these\ninto the Helm config file later."),(0,i.kt)("h3",{id:"iam-roles-to-create"},"IAM Roles to create"),(0,i.kt)("p",null,"Here are the services you want to create IAM admin users for, and the associated permissions you want to\ngrant them:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"S3: ",(0,i.kt)("inlineCode",{parentName:"li"},"AmazonS3FullAccess, CloudFrontFullAccess")),(0,i.kt)("li",{parentName:"ul"},"SNS: ",(0,i.kt)("inlineCode",{parentName:"li"},"AmazonSNSFullAccess"))),(0,i.kt)("p",null,"You'll also need to create an IAM user that GitHub Actions can use to access the cluster and push/pull\nDocker images from ECR. By convention, we call this user 'EKSUser', and it needs these\npermissions: ",(0,i.kt)("inlineCode",{parentName:"p"},"AmazonEKSClusterPolicy, AmazonEKSWorkerNodePolicy, AmazonEKSServicePolicy, AmazonElasticContainerRegistryPublicFullAccess, AmazonEC2ContainerRegistryFullAccess")),(0,i.kt)("h3",{id:"creating-new-credentials-for-an-iam-user"},"Creating new credentials for an IAM user"),(0,i.kt)("p",null,"If you ever lose the secret to a user, or want to make new credentials for whatever reason, go to\nIAM->Users and click on that user. Click on the 'Security credentials' tab, and under 'Access keys' you\nshould see a button 'Create access key' and, underneath that, 0-2 existing keys with some information\nabout them and an 'x' on the far right to delete it. If there are two keys for that user, you\nmust deactivate and delete one of them before making a new one."),(0,i.kt)("p",null,"Click the Create button, then make sure to save the public and secret keys somewhere and put them into\nthe Helm config file."),(0,i.kt)("h2",{id:"create-rds-box"},"Create RDS box"),(0,i.kt)("p",null,"Ethereal Engine is backed by a SQL server. We use MariaDB in development, but it has also been run on AWS with\nAurora without issue. Most other versions of SQL should work but have not been explicitly tested."),(0,i.kt)("h3",{id:"accessing-rds-box-from-an-external-machine"},"Accessing RDS box from an external machine"),(0,i.kt)("p",null,"By default, an RDS box is only accessible from within the VPC it's located.\nIf you want to be able to connect to it from outside that VPC, you'll need to either set up a bastion box\nand SSH into that box, or make the RDS box publicly accessible."),(0,i.kt)("p",null,"Setting up a bastion box is not covered here at this time. The steps to make it public will be noted\nbelow by ",(0,i.kt)("strong",{parentName:"p"},"Make RDS public")),(0,i.kt)("h3",{id:"create-rds-instance"},"Create RDS instance"),(0,i.kt)("p",null,"Go to RDS and click the Create Database button. Most options can be left at their default values.\nUnder Settings, give a more descriptive DB cluster identifier. The Master Username can be left as admin;\nenter a Master Password and then enter it again in Confirm Password."),(0,i.kt)("p",null,"Under DB instance class, pick an option that best meets your pricing needs."),(0,i.kt)("p",null,"Under Availability and Durability, it's recommended that you leave it on the default of\nmaking an Aurora Replica in another AZ."),(0,i.kt)("p",null,"Under Connectivity, make sure that it's in the VPC that was made as part of the EKS cluster."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Make RDS public"),"\nIf you want to be able to access it externally, you should set Public Access to 'Yes'."),(0,i.kt)("p",null,"Under VPC security group, select the ones titled\n",(0,i.kt)("inlineCode",{parentName:"p"},"eksctl-<EKS_cluster_name>-cluster-ClusterSharedNodeSecurityGroup-<random_string>")," and\n",(0,i.kt)("inlineCode",{parentName:"p"},"eks-clustersg-<EKS_cluster_name>-<random_string>"),"."),(0,i.kt)("p",null,"Open the top-level Additional Configuration dropdown (not the one within Connectivity). Under Database Options-> Initial Database Name,\nname the default database and save this for later use in the Helm config file."),(0,i.kt)("p",null,"Finally, click the Create Database button at the very bottom of the page."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Make RDS Public")," You will need to add a Security Group to the RDS instance that allows traffic over port\n3306 (or whatever port you chose to run it on). You can have this SG only let in traffic from your IP address(es)\nif you want to be very secure about this, or from anywhere (0.0.0.0/0) if you're less concerned about someone\ngetting access."),(0,i.kt)("p",null,"Some values to note for dev/prod.template.values.yaml:\nsql.database will be what you entered for Initial Database Name\nsql.user and sql.password will be the name and password of the admin user\nsql.host will be the Endpoint of the RDS instance/cluster; find this by going to RDS -> Databases,\nclicking on either the lone DB identifier (if made in a single AZ) or the top-level regional cluster\nidentifier (if set up in a multi-AZ deployment); the look for Endpoint (single-AZ) or, if multi-AZ,\nthe Endpoint name that has type 'Writer instance'."),(0,i.kt)("h2",{id:"edit-security-group-to-allow-instanceserver-traffic-into-vpc"},"Edit security group to allow instanceserver traffic into VPC"),(0,i.kt)("p",null,"You'll need to edit the new cluster's main security group to allow instanceserver traffic.\nOn the AWS web client, go to EC2 -> Security Groups. There should be three SGs that have\nthe node's name somewhere in their name; look for the one that is in the form\n",(0,i.kt)("inlineCode",{parentName:"p"},"eks-cluster-sg-<cluster_name>-<random_numbers>"),". It should NOT end with /ControlPlaneSecurityGroup\nor /ClusterSharedNodeSecurityGroup.\nClick on that, then the Inbound Rules tab, then click Edit Inbound Rules."),(0,i.kt)("p",null,"You'll need to add two rule sets:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Type: Custom UDP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')"),(0,i.kt)("li",{parentName:"ul"},"Type: Custom TCP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')")),(0,i.kt)("h2",{id:"create-route-53-hosted-zone-and-set-up-acm-certificates"},"Create Route 53 Hosted Zone and set up ACM certificates"),(0,i.kt)("p",null,"Before installing Nginx to the cluster, you'll need to have all of the networking squared away.\nThis requires creating the necessary SSL certificates and creating some DNS records to point\nvarious subdomains to the right place."),(0,i.kt)("h3",{id:"purchase-and-register-domain-through-route53-optional"},"Purchase and register domain through Route53 (optional)"),(0,i.kt)("p",null,"If you do not have a domain for your application already, it's easiest to register it through Route53.\nGo to Route53->Domains->Registered domains, then click the 'Register Domain' button, and follow the\nworkflow to register a domain name."),(0,i.kt)("h3",{id:"create-route-53-hosted-zone"},"Create Route 53 Hosted Zone"),(0,i.kt)("p",null,"In the AWS web client, go to Route 53. Make a hosted zone for the domain you plan to use for\nyour setup of Ethereal Engine. You'll be coming back here later to create DNS records."),(0,i.kt)("p",null,"Open the Hosted zone, then click on 'Hosted zone details' to see more information. The value 'Hosted zone id'\nis used in the dev/prod.values.yaml file for 'ROUTE53_HOSTED_ZONE_ID'"),(0,i.kt)("h4",{id:"point-external-registrar-subdomains-to-use-route53-nameservers-only-if-your-domain-is-registered-outside-route53"},"Point external registrar subdomains to use Route53 Nameservers (only if your domain is registered outside Route53)"),(0,i.kt)("p",null,"If you already have a domain registered with another registrar service, you'll need to add some DNS records\nin there to point the specific subdomains you'll be using to AWS' nameservers."),(0,i.kt)("p",null,"First, go to Route53->Hosted Zones and open the domain you'll be using by clicking on the domain name (or\nhighlighting the row and clicking the 'View details' button). There should be two records under Records.\nLook for the one of type 'NS'; under 'Value/Route traffic to', there should be four lines that all start\nwith 'ns-'. These will be used shortly."),(0,i.kt)("p",null,"Go to your external registrar and go to the DNS records page. For each subdomain that will be in use, you\nneed to add four records of type 'NS'. The Name wil be the subdomain, and the Nameserver will be one of\nthe four lines under the 'NS'. You need a record for each of the four lines."),(0,i.kt)("p",null,"If you're setting up multiple deployments, e.g. both a dev and prod deployment, you'll need a set of four\nNS records for each subdomain that those deployments will be behind."),(0,i.kt)("h3",{id:"create-certificates-with-acm"},"Create certificates with ACM"),(0,i.kt)("p",null,"Go to Amazon Certificate Manager. If there are no certs in that region, click on Get Started under Provision Certificates,\notherwise click on Request a Certificate."),(0,i.kt)("p",null,"You should select Request a Public Certificate, then select Request a Certificate. The next page\nshould be headed Add Domain Names. You should add both the top-level domain, such as ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine.org"),",\nas well as a wildcard for all subdomains e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"*.etherealengine.org"),", then click Next."),(0,i.kt)("p",null,"Choose DNS Validation on the next page and click Next. You can skip adding tags and just click Review,\nthen Confirm on the final page."),(0,i.kt)("p",null,"You should be sent to a page headed Validation. Click on the arrow next to each domain to open more\noptions. Click on the button Create Record in Route 53 to open a confirmation modal, and in that modal\nclick Create."),(0,i.kt)("p",null,"As it indicates, it can take up to 30 minutes for these domains to be validated. If you click on Complete\nafter triggering the record creation for each of them, you should be sent back to the Certificates page.\nOpening the cert you just made will show the validation status of each domain."),(0,i.kt)("p",null,"If you open the details of this certificate, there should be a field 'ARN' with a value that looks\nsomething like ",(0,i.kt)("inlineCode",{parentName:"p"},"arn:aws:acm:<region>:<AWS account ID>:certificate/<a UUID>"),". Take note of this for later,\nwhen you go to install ingress-nginx."),(0,i.kt)("h4",{id:"if-you-are-serving-client-files-from-client-or-api-pods"},"If you are serving client files from client or API pods"),(0,i.kt)("p",null,"You should follow the above instructions to make a second certificate for ",(0,i.kt)("inlineCode",{parentName:"p"},"resources.<domain>"),".\nNote that this certificate MUST be made in us-east-1, regardless of which region everything else is\nset up in; as of this writing, CloudFront can only use certificates in us-east-1."),(0,i.kt)("h4",{id:"if-you-are-serving-client-files-from-the-storage-provider"},"If you are serving client files from the Storage Provider"),(0,i.kt)("p",null,"You should follow the above instructions to make a second certificate for ",(0,i.kt)("inlineCode",{parentName:"p"},"<RELEASE_NAME>.<domain>"),".\nNote that this certificate MUST be made in us-east-1, regardless of which region everything else is\nset up in; as of this writing, CloudFront can only use certificates in us-east-1."),(0,i.kt)("h2",{id:"install-agones-ingress-nginx-and-a-copy-of-redis-for-each-deployment"},"Install Agones, ingress-nginx, and a copy of redis for each deployment"),(0,i.kt)("p",null,"Now that the cluster is up and running, we can install everything onto it.\nWhen you created the cluster with eksctl, it should have created a context pointing to\nit in kubectl. Run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all of the contexts it knows about;\nthe one with a star next to it should be named ",(0,i.kt)("inlineCode",{parentName:"p"},"<your_AWS_username>@<cluster_name>"),".\nIf that isn't present, you'll have to edit the configuration to make the appropriate context."),(0,i.kt)("p",null,"You next need to add the Agones, ingress-nginx, and redis Helm charts to helm by running\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add agones https://agones.dev/chart/stable"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add redis https://charts.bitnami.com/bitnami"),".\nYou should also at this time add Ethereal Engine's repo via ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add etherealengine https://helm.etherealengine.org"),"."),(0,i.kt)("p",null,"If you ever suspect that a chart is out-of-date, run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo update")," to update all of them to the latest."),(0,i.kt)("h3",{id:"install-agones"},"Install Agones"),(0,i.kt)("p",null,"From the top level of this repo, run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones"),".\nThis says to install a service called 'agones' from the 'agones' package in the 'agones' chart, and to configure it with\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," that can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,i.kt)("h3",{id:"install-redis-for-each-deployment"},"Install redis for each deployment"),(0,i.kt)("p",null,"Each deployment of Ethereal Engine uses a redis cluster for coordinating the 'feathers-sync' library.\nEach redis deployment needs to be named the same as the deployment that will use it; for an\nEthereal Engine deployment named 'dev', the corresponding redis deployment would need to be named\n'dev-redis'."),(0,i.kt)("p",null,"Run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/redis-values.yaml> <RELEASE_NAME>-redis redis/redis")," to install, e.g.\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/redis-values.yaml> dev-redis redis/redis"),"."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/redis-values.yaml"},"redis-values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("p",null,"If you named the redis nodegroup something other than 'ng-redis-1', you'll have to alter the value in\n",(0,i.kt)("inlineCode",{parentName:"p"},"redis-values.yaml")," in two places to your redis nodegroup name.\nIf you didn't create a nodegroup just for redis, you must omit the ",(0,i.kt)("inlineCode",{parentName:"p"},"-f </path/to/redis-values.yaml>"),",\nas that config makes redis pods run on a specific nodegroup."),(0,i.kt)("h4",{id:"installing-redis-as-part-of-ethereal-engine-chart-not-recommended-for-production"},"Installing redis as part of Ethereal Engine chart (not recommended for production)"),(0,i.kt)("p",null,"Redis can be installed as part of the Ethereal Engine chart so long as the config file for the Ethereal Engine installation has 'redis.enabled' set to true.\nIn that case, you should skip the above step of installing redis separately. This is not recommended for production\nenvironments, though, since upgrades to an Ethereal Engine installation will usually reboot the redis servers,\nleading all of the instanceservers to crash due to their redis connections being severed."),(0,i.kt)("p",null,"This breaks Agones' normal behavior of keeping Allocated instanceservers running until every user has left and slowly replacing\nold Ready instanceservers with new ones, maintaining an active pool of instanceservers at all times. You will encounter a period\nof time where there are no active instanceservers at all, which is not recommended, and all instanceservers in use\nwill immediately go down."),(0,i.kt)("h3",{id:"install-ingress-nginx"},"Install ingress-nginx"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"This step cannot finish until the associated ACM Certificate is fully validated"),"\nOpen local version of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/nginx-ingress-aws-values.yml"},"nginx-ingress-aws-values.yml")," file. Take note of the line\n",(0,i.kt)("inlineCode",{parentName:"p"},'service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "<ACM Certificate ARN for SSL>"'),"\nReplace the bit in angle brackets, including the angle brackets, with the ARN of the certificate\nyou made for the top-level domain and all wildcarded subdomains, e.g.\n",(0,i.kt)("inlineCode",{parentName:"p"},'service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-1:103947711118:certificate/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"')),(0,i.kt)("p",null,"Do not commit this file with the ARN inserted; once you've completed this step, revert the file back\nto the state it was committed in."),(0,i.kt)("p",null,"From the top level of this repo, run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/nginx-ingress-aws-values.yml> nginx ingress-nginx/ingress-nginx"),"\nThis says to install a service called 'nginx' from the 'ingress-nginx' package in the 'ingress-nginx' chart, and to configure it with\na file found at ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/nginx-ingress-aws-values.yml"},"nginx-ingress-aws-values.yml"),"."),(0,i.kt)("h2",{id:"set-up-simple-email-service-optional"},"Set up Simple Email Service (optional)"),(0,i.kt)("p",null,"If you want to enable email magiclink login, you will need to set up Simple Email Service (SES)."),(0,i.kt)("p",null,"In the AWS web client, go to SES -> Configuration -> Verified Identities. Click Create Identity, then under 'Identity type'\nselect 'Domain'. Enter the top-level domain under the 'Domain' field. Finally, click the 'Create identity' button."),(0,i.kt)("h3",{id:"create-smtp-credentials"},"Create SMTP credentials"),(0,i.kt)("p",null,"You need to create SMTP credentials in order to authorize SES. These will show up as an IAM user,\nbut you must go through an SES-specific process to get valid credentials; just creating an IAM user\nwith SESFullAccess will not work."),(0,i.kt)("p",null,"Go to an SES page and select 'SMTP Settings', then click the button 'Create SMTP Credentials'.\nYou can leave the default IAM User Name as-is; click the Create button. You should be taken to a screen\nsays a user has been created successfully. Click on 'Show User SMTP Security Credentials'."),(0,i.kt)("p",null,"You will see a Username and Password. These credentials will go into the Helm config file, under\nAWS_SMTP_USER and AWS_SMTP_PASS, respectively. You must also fill in the region that you've created these credentials\nin, replacing <SES_REGION> in api.extraEnv.SMTP_HOST."),(0,i.kt)("h3",{id:"move-ses-out-of-sandbox"},"Move SES out of Sandbox"),(0,i.kt)("p",null,"By default, SES domains are in Sandbox mode, where they can only send emails to verified email addresses.\nTo request that the domain be moved out of Sandbox mode, go to SES->Email Sending->Sending Statistics.\nClick on the button 'Edit your account details' to open the modal. Set 'Enable Production Access' to Yes,\nleave Mail type on 'Transactional', then fill in the Website URL, add a Use case description (basically\njust assure them that this is for account login only, not anything else), click the checkbox to agree\nto their TOD, and click the button 'Submit for review'."),(0,i.kt)("p",null,"It may take up to a few days for them to take action. If the request is rejected, address their concerns.\nOnce you have been approved, email login should work for any email address."),(0,i.kt)("h4",{id:"verifying-test-emails"},"Verifying test emails"),(0,i.kt)("p",null,"Before you have production use for your SES domain, in order to log in you'll have to verify specific email\naddresses with SES. Go to SES->Identity Management->Email Addresses. Click on the button 'Verify a New Email\nAddress'. Enter the address you want to test with, then click 'Verify This Email Address'. You should soon\nreceive an email with a link to verify it (it may go to your Spam folder). Once you've followed the link,\nyou can log in with that address."),(0,i.kt)("h2",{id:"set-up-simple-notification-service-optional"},"Set up Simple Notification Service (optional)"),(0,i.kt)("p",null,"If you want to enable text message-based magiclink login, you will need to set up Simple Notification Service (SNS)."),(0,i.kt)("p",null,"In the AWS web client, go to SNS -> Topics and Create a new topic.\nGive it a name, and selected 'Standard' as the type, then click Create Topic."),(0,i.kt)("h2",{id:"set-up-s3-bucket-for-static-resources-and-cloudfront-distribution"},"Set up S3 bucket for static resources and Cloudfront distribution"),(0,i.kt)("p",null,"Various static files are stored in S3 behind a Cloudfront distribution. If you are serving the client files\nfrom the Storage Provider, then all client files will be stored and served from these as well."),(0,i.kt)("h3",{id:"create-s3-bucket"},"Create S3 bucket"),(0,i.kt)("p",null,"In the AWS web client, go to S3 -> Buckets and click Create Bucket.\nName the bucket ",(0,i.kt)("inlineCode",{parentName:"p"},"<name>-static-resources"),", e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine-static-resources"),", and have it be in Region us-east-1.\nUnder Object Ownership, select 'ACLs enabled', and under that select 'Object Writer'.\nUnder Block Public Access Settings For The Bucket, uncheck the checkbox Block ",(0,i.kt)("em",{parentName:"p"},"all")," Public Access;\nyou need the bucket to be publicly accessible.\nCheck the box that pops up confirming that you know the contents are public.\nAll other settings can be left to their default values; click Create Bucket."),(0,i.kt)("p",null,"Open the bucket's settings and go the Permissions tab. Midway down is 'Access control list'. Edit that, and\nCheck the boxes for Objects:List and Bucket ACL:Read for 'Everyone (public access)'. Click the box with the\nwarning label that appears that says \"I understand the effects of these changes on my objects and buckets\",\nthen click Save Changes.\nAt the bottom of the Permissions tab is a Cross-origin Resource Sharing (CORS) box.\nIt should have the following settings; if not, click Edit and copy this in:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'[\n {\n "AllowedHeaders": [],\n "AllowedMethods": [\n "HEAD",\n "GET",\n "POST"\n ],\n "AllowedOrigins": [\n "*"\n ],\n "ExposeHeaders": []\n }\n]\n')),(0,i.kt)("h3",{id:"create-cloudfront-distribution"},"Create Cloudfront distribution"),(0,i.kt)("p",null,"In the AWS web client, go to Cloudfront -> Distributions and click on Create Distribution.\nUnder 'Web', click on Get Started."),(0,i.kt)("p",null,"Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin"),", click on the text box under ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin domain"),", and select the name of the S3 bucket you just made.\nThe ",(0,i.kt)("inlineCode",{parentName:"p"},"Name")," field should be automatically populated, and should be left as whatever that value is."),(0,i.kt)("p",null,"Several fields in ",(0,i.kt)("inlineCode",{parentName:"p"},"Default cache behavior")," will be changed."),(0,i.kt)("p",null,"Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Viewer -> Viewer protocol policy"),", select 'Redirect HTTP to HTTPS'\nUnder ",(0,i.kt)("inlineCode",{parentName:"p"},"Viewer -> Allowed HTTP methods"),", select 'GET, HEAD, OPTIONS', and check ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache HTTP methods -> OPTIONS"),"."),(0,i.kt)("p",null,"In ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache key and origin requests"),", leave it on ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy and origin request policy"),".\nIf this option is not available, see the below subsection for ",(0,i.kt)("inlineCode",{parentName:"p"},"Legacy cache settings")),(0,i.kt)("p",null,"For ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy"),", you will need to make a new policy, which is easily done by clicking the link ",(0,i.kt)("inlineCode",{parentName:"p"},"Create policy"),"\nunderneath the selector; this will open a new tab. Name this policy anything you want, e.g. 'Cached-on-headers',\nthen under ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache key settings"),", click on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Headers")," selector and select 'Include the following headers'. A new\nselector should appear under that titled ",(0,i.kt)("inlineCode",{parentName:"p"},"Add header"),". Click the selector, and check 'Origin',\n'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away from the menu. Click the 'Create'\nbutton to create the new policy."),(0,i.kt)("p",null,"Once the policy has been created, go back to the tab that you were creating the CloudFront distribution in.\nClick the refresh button to the right of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy")," selector to fetch your new policy, then click the selector,\nand your new policy should appear in the selector at the bottom of the list under the header 'Custom'. Select it."),(0,i.kt)("p",null,"For ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin request policy"),", select the option 'CORS-S3Origin'."),(0,i.kt)("p",null,"You should also make a custom response header policy so that files are served with the ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin-Agent-Cluster"),"\nheader, which will tell most browsers to isolate resources for same-site cross-origin requests. To do that,\nyou will need to make a custom response header policy. Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Response headers policy"),", select ",(0,i.kt)("inlineCode",{parentName:"p"},"Create Policy"),".\nThis will open a separate tab. Name this something like ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin-Agent-Cluster"),", then under ",(0,i.kt)("inlineCode",{parentName:"p"},"Custom headers"),",\nclick ",(0,i.kt)("inlineCode",{parentName:"p"},"Add header"),". For name, enter ",(0,i.kt)("inlineCode",{parentName:"p"},"Origin-Agent-Cluster"),", and for ",(0,i.kt)("inlineCode",{parentName:"p"},"Value"),", enter ",(0,i.kt)("inlineCode",{parentName:"p"},"?1"),". Then click the ",(0,i.kt)("inlineCode",{parentName:"p"},"Create"),"\nbutton at the bottom."),(0,i.kt)("p",null,"Go back to the tab where you were creating the Cloudfront distribution. Click the refresh button to the right of\nthe ",(0,i.kt)("inlineCode",{parentName:"p"},"Response headers policy")," selector to fetch the new policy, then click the selector, and your new policy should\nappear in the selector at the bottom of the list under the header ",(0,i.kt)("inlineCode",{parentName:"p"},"Custom"),". Select it."),(0,i.kt)("p",null,"Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Settings"),", you can change ",(0,i.kt)("inlineCode",{parentName:"p"},"Price class")," to 'Use Only North America and Europe' to save some money.\nFor Alternate Domain Names, click 'Add item', then in the text box that appears, enter 'resources.",(0,i.kt)("inlineCode",{parentName:"p"},"<domain>"),"', e.g.\n",(0,i.kt)("inlineCode",{parentName:"p"},"resources.etherealengine.org"),", or '<RELEASE_NAME>.",(0,i.kt)("inlineCode",{parentName:"p"},"<domain>"),"', e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"dev.etherealengine.org"),", depending on\nwhether you are serving the client files from client/API pods or the Storage Provider, respectively.\nUnder ",(0,i.kt)("inlineCode",{parentName:"p"},"Custom SSL Certificate"),", click on the selector that says 'Choose certificate', then select the\n'resources.",(0,i.kt)("inlineCode",{parentName:"p"},"<domain>"),"'/'",(0,i.kt)("inlineCode",{parentName:"p"},"<RELEASE_NAME>.<domain>"),"' certificate you made earlier. If you are serving the client\nfiles from the Storage Provider, under ",(0,i.kt)("inlineCode",{parentName:"p"},"Default root object"),", enter ",(0,i.kt)("inlineCode",{parentName:"p"},"client/index.html"),"; if you are serving\nthe client files from client/API pods, leave this blank."),(0,i.kt)("p",null,"Everything else can be left at the default values, click Create Distribution."),(0,i.kt)("h4",{id:"legacy-cache-settings"},"Legacy cache settings"),(0,i.kt)("p",null,"If for some reason ",(0,i.kt)("inlineCode",{parentName:"p"},"Cache policy and origin request policy")," is not available for you, and you have to use\n",(0,i.kt)("inlineCode",{parentName:"p"},"Legacy cache settings"),", the under ",(0,i.kt)("inlineCode",{parentName:"p"},"Headers"),", select 'Include the following headers'. Under ",(0,i.kt)("inlineCode",{parentName:"p"},"Add header")," that appears,\nclick on the selector titled 'Select headers', and in the menu that opens, check 'Host', 'Origin',\n'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away."),(0,i.kt)("h2",{id:"set-up-dns-records"},"Set up DNS records"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"The Nginx Load Balancer must be fully set up and running before this step can be completed")),(0,i.kt)("p",null,"In the AWS web client, go to Route 53, then go into the Hosted Zone you made earlier.\nClick on Create Record. If it starts you under Quick Create Record, click the link\n'Switch to Wizard'; it's not necessary, but the wizard is handy."),(0,i.kt)("p",null,"Under Routing Policy, leave it on Simple Routing and click Next. Then click Define Simple Record."),(0,i.kt)("p",null,"The first record should be for the top-level domain, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"etherealengine.org"),", so leave the Record Name\ntext field blank. Under Value/Route Traffic To, click on the dropdown and select\nAlias to Network Load Balancer. Select the region that your cluster is in.\nWhere it says Choose Load Balancer, click the dropdown, and select the NLB that was created.\nLeave the Record Type as 'A - Route traffic to an IPv4 address and some AWS resources', then click\nDefine Simple Record."),(0,i.kt)("p",null,"You can keep clicking Define Simple Record to make more records in one batch. When you're\ndone, click Create Records."),(0,i.kt)("p",null,"You should make the following 'A' records to the loadbalancer, substituting your domain for 'etherealengine.org':"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"*.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"@.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"api-dev.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"api.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"dev.etherealengine.org -- Only if serving client files from client/API pods"),(0,i.kt)("li",{parentName:"ul"},"instanceserver.etherealengine.org"),(0,i.kt)("li",{parentName:"ul"},"instanceserver-dev.etherealengine.org")),(0,i.kt)("p",null,"You also need to make an 'A' record pointing 'resources.etherealengine.org' or '<RELEASE_NAME>.etheralengine.org' to the\nCloudFront distribution you made earlier.\nInstead of 'Alias to Network Load Balancer', select 'Alias to Cloudfront distribution', then click the text box that appears\nthat says 'Choose distribution'. A selector should appear with the subdomain you're routing as well as the Cloudfront\ndistribution's domain name, which you should click on. Then click Define simple record."),(0,i.kt)("h2",{id:"create-github-fork-of-ethereal-engine-repository"},"Create GitHub fork of Ethereal Engine repository."),(0,i.kt)("p",null,"The Ethereal Engine codebase is most easily deployed by forking it and configuring some Secrets so that the included GitHub\nActions can run the deployment for you. You can run all of the commands that the ",(0,i.kt)("inlineCode",{parentName:"p"},"<dev/prod>"),"-deploy action runs manually\nif you so choose, and in that case, you don't need to fork the GH repo."),(0,i.kt)("p",null,"Go to ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine"},"https://github.com/etherealengine/etherealengine"),". In the upper right-hand corner, there's a button 'Fork'. Click that,\nthen click the account/organization you wish to fork it to. You should be taken to your fork in a short time."),(0,i.kt)("p",null,"You'll need to set several Secrets (runtime variables) for GitHub Actions. By default GitHub Actions should be fully\nenabled, but you can double-check by going to Settings->Actions. Allow All Actions should be selected under Actions\nPermissions."),(0,i.kt)("p",null,"Next click on Secrets under Settings. There should be none by default. Click on New Repository Secret near the top of\nthis page to make a new one. You will need to make several Secrets with the following Names and Values:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"EKS_AWS_ACCESS_KEY -> The public Key of the EKSUser IAM user"),(0,i.kt)("li",{parentName:"ul"},"AWS_REGION -> The region of your ECR repos and EKS cluster"),(0,i.kt)("li",{parentName:"ul"},"EKS_AWS_SECRET -> The secret key of the EKSUser IAM user"),(0,i.kt)("li",{parentName:"ul"},"CLUSTER_NAME -> The name of the EKS cluster"),(0,i.kt)("li",{parentName:"ul"},"DEPLOYMENTS_ENABLED -> Set to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")),(0,i.kt)("li",{parentName:"ul"},"DEV_REPO_NAME -> The base name of the dev ECR repository, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"etherealengine-dev")," (all references to the builder and service repos will append ",(0,i.kt)("inlineCode",{parentName:"li"},"-builder"),"/",(0,i.kt)("inlineCode",{parentName:"li"},"-<service>")," to this value)"),(0,i.kt)("li",{parentName:"ul"},"DOCKER_LABEL -> This can be almost anything, but you can use ",(0,i.kt)("inlineCode",{parentName:"li"},"lagunalabs/etherealengine")),(0,i.kt)("li",{parentName:"ul"},"ECR_URL -> The root ECR_URL for your repos, i.e. everything before the ",(0,i.kt)("inlineCode",{parentName:"li"},"/etherealengine-dev-builder"),", e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"11111111111.dkr.ecr.us-west-1.amazonaws.com")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"public.ecr.aws/a1b2c3d4")),(0,i.kt)("li",{parentName:"ul"},"PRIVATE_ECR -> Set this to ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," if your ECR repos are private, if they're public you don't need to set this at all")),(0,i.kt)("p",null,"If you go to the Actions Tab, you might see a few workflow runs with green checkmarks. If so, you'll be re-running the\n",(0,i.kt)("inlineCode",{parentName:"p"},"dev-deploy")," workflow shortly; its initial run just ran a check to see if it should do a deployment based on\n",(0,i.kt)("inlineCode",{parentName:"p"},"DEPLOYMENTS_ENABLED"),", and since that wasn't set to true, it didn't do anything else. Now that that's set to true,\nre-running it will trigger a deployment."),(0,i.kt)("p",null,"If you're asked to enable actions when going to the tab, and there are no runs listed after enabling actions, then you'll have to\ntrigger the workflow by pushing new code to the dev branch."),(0,i.kt)("h2",{id:"grant-eksuser-access-to-cluster"},"Grant EKSUser access to cluster"),(0,i.kt)("p",null,"By default, only the IAM user who set up an EKS cluster may access it.\nIn order to let other users access the cluster, you must apply an aws-auth configmap to the cluster\ngranting access to specific IAM users. A template of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/aws-auth-template.yml"},"aws-auth-template.yml")," file can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,i.kt)("p",null,"You'll need to provide a few values for this file. To find ",(0,i.kt)("inlineCode",{parentName:"p"},"<rolearn>"),", in AWS go to EKS->Clusters->\n",(0,i.kt)("inlineCode",{parentName:"p"},"<your cluster>"),"->Compute->Select a nodegroup. In the details should be 'Node IAM Role ARN'; copy this\nand replace ",(0,i.kt)("inlineCode",{parentName:"p"},"<rolearn>")," in the aws-auth file. ",(0,i.kt)("inlineCode",{parentName:"p"},"<account_id>")," is the ID of your AWS account; in the upper\nright corner of the AWS client should be ",(0,i.kt)("inlineCode",{parentName:"p"},"<your_username>@<abcd-1234-efgh>"),". The 12-character string\nafter the @ is the account ID. Make sure to remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"-"),"'s from the account ID when pasting it in.\n",(0,i.kt)("inlineCode",{parentName:"p"},"<IAM_username>")," is the username of the IAM user you want to give access, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"EKSUser"),"."),(0,i.kt)("p",null,"You can add multiple users by copying the ",(0,i.kt)("inlineCode",{parentName:"p"},"- groups:")," section under ",(0,i.kt)("inlineCode",{parentName:"p"},"mapUsers"),", e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," mapUsers: |\n - groups:\n - system:masters\n userarn: arn:aws:iam::abcd1234efgh:user/EKSUser\n username: EKSUser\n - groups:\n - system:masters\n userarn: arn:aws:iam::acbd1234efgh:user/FSmith\n username: FSmith\n")),(0,i.kt)("p",null,"When the aws-auth config file is filled in, just run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl apply -f path/to/aws-auth.yml"),"."),(0,i.kt)("h2",{id:"deploy-to-eks-using-helm"},"Deploy to EKS using Helm"),(0,i.kt)("p",null,"With all of the networking set up, you can finally deploy the codebase to EKS.\nThere's a couple of steps to this, which will involve deploying things with most but not all of the needed\nconfiguration values, and then letting the deployment process fill in the rest."),(0,i.kt)("h3",{id:"fill-in-helm-config-file-with-variables"},"Fill in Helm config file with variables"),(0,i.kt)("p",null,"Template Helm config files for dev and prod deployments can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs"},"configs")," <dev/prod>.template.values.yaml.\nBefore filling them in, make a copy elsewhere, call that '<dev/prod>.values.yaml', and edit that copy.\nBoth the builder and main deployments should use the same config file. When the builder seeds the database,\nit needs a number of values that only need to be configured for the other services, so all of the values\nneed to be defined in one config file."),(0,i.kt)("p",null,"There are many fields to fill in, most marked with ",(0,i.kt)("inlineCode",{parentName:"p"},"<>"),". Not all are necessary for all situations - if you're not\nusing social login, for instance, you don't need credentials for Github/Google/Facebook/etc."),(0,i.kt)("h3",{id:"configuration-variables-of-note"},"Configuration variables of note"),(0,i.kt)("p",null,"Here are some configuration variables that you'll probably need to change based on your specific setup"),(0,i.kt)("h4",{id:"apiinstanceservertaskserverextraenvauth_secret"},"<api/instanceserver/taskserver>.extraEnv.AUTH_SECRET"),(0,i.kt)("p",null,"This is a secret value that is used to sign the JWTs that authenticate users.\nYou can use any string for this value, and a randomly-generated one of sufficient length,\ni.e. 32 or more characters, will suffice. If this is changed after some users have signed\nin, their login credentials won't work any more."),(0,i.kt)("h4",{id:"apiclienttaskserveraffinitynodeaffinity"},"<api/client/taskserver>.affinity.nodeAffinity"),(0,i.kt)("p",null,"Within the sections of the config for the api, client, instanceserver, etc., is a section that looks\nsomething like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," affinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: eks.amazonaws.com/nodegroup\n operator: In\n values:\n - ng-1\n")),(0,i.kt)("p",null,"The value, ",(0,i.kt)("inlineCode",{parentName:"p"},"ng-1")," in this example, must be changed to match whatever the name of the nodegroup that\nthat service will be running on, e.g. if you create a nodegroup for the instanceservers called\n",(0,i.kt)("inlineCode",{parentName:"p"},"abcd-instanceservers-5"),", then you'd use that value under ",(0,i.kt)("inlineCode",{parentName:"p"},"values:")),(0,i.kt)("p",null,"If your EKS setup created a nodegroup for you, and you want to use that for the api, client, and\ntask servers, make sure to change the affinity value for them to whatever EKS named the\ninitial nodegroup."),(0,i.kt)("h4",{id:"builderextraenvprivate_ecr"},"builder.extraEnv.PRIVATE_ECR"),(0,i.kt)("p",null,'If you\'re using a private ECR repo, set this to "true" in the builder config file.'),(0,i.kt)("h4",{id:"everythingimagerepository"},"(everything).image.repository"),(0,i.kt)("p",null,"You'll need to replace every <repository_name> with the full ECR_URL of your non-builder repos, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"abcd1234efgh.dkr.ecr.us-west-1.amazonaws.com/etherealengine-dev-api"),".\nEach service has to have the proper ",(0,i.kt)("inlineCode",{parentName:"p"},"-<service>")," suffix on it, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"-api"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"-client"),", etc."),(0,i.kt)("h4",{id:"github_client_idgithub_client_secret"},"GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET"),(0,i.kt)("p",null,"If you plan to backup Projects you create in the editor to GitHub, or install project from GitHub, it is necessary\nto set up the OAuth app that will facilitate this before the initial installation.\nSee ",(0,i.kt)("a",{parentName:"p",href:"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects"},"this document")," for\nmore information, and enter the appropriate ID/secret in these variables."),(0,i.kt)("h3",{id:"run-helm-install"},"Run Helm install"),(0,i.kt)("p",null,"Run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME>-builder etherealengine/etherealengine-builder"),"\nand then run ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME> etherealengine/etherealengine")),(0,i.kt)("p",null,"This will spin up the main and builder deployments using the Helm config file, <dev/prod>.values.yaml.\nNeither will fully work yet, since there's no valid image in the repos yet. The GitHub\nActions and builder processes will make those images and update the deployments with the tags of the images they've built\nso that they can pull down and use those images."),(0,i.kt)("h2",{id:"kick-off-github-actions"},"Kick off GitHub Actions"),(0,i.kt)("p",null,"In GitHub, if you go to back to the Actions tab, you should see a ",(0,i.kt)("inlineCode",{parentName:"p"},"dev-deploy")," action. Click on it, and you should see\na page showing its status, which should be all green checkmarks or indicators that things didn't run. In the upper\nright, click ",(0,i.kt)("inlineCode",{parentName:"p"},"Re-run all jobs"),". This will start it again, and now that ",(0,i.kt)("inlineCode",{parentName:"p"},"DEPLOYMENTS_ENABLED")," is set to true, it should\nattempt to build and deploy the builder."),(0,i.kt)("p",null,"(If actions were disabled at first, you'll have to merge additional code into the dev branch to get it to start the dev-deploy process)"),(0,i.kt)("h3",{id:"overview-of-the-build-process"},"Overview of the build process"),(0,i.kt)("p",null,"The full build and deployment process works like this:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"GitHub Actions builds just enough of the Ethereal Engine monorepo to fetch any installed Ethereal Engine projects."),(0,i.kt)("li",{parentName:"ol"},"GitHub Actions pushes this builder Docker image to the repo ",(0,i.kt)("inlineCode",{parentName:"li"},"etherealengine-<release>-builder")," in ECR"),(0,i.kt)("li",{parentName:"ol"},"GitHub Actions updates the builder deployment to point to the builder image it just created."),(0,i.kt)("li",{parentName:"ol"},"The builder deployment spins up the builder Docker image on its single node"),(0,i.kt)("li",{parentName:"ol"},"The builder connects to the deployment's database and checks if there is a table ",(0,i.kt)("inlineCode",{parentName:"li"},"user"),". This is a proxy\nfor the database being seeded; if it does not exist, it seeds the database with the basic Ethereal Engine schema,\nseeds the default project into the database and storage provider, and seeds various types."),(0,i.kt)("li",{parentName:"ol"},"The builder downloads any Ethereal Engine projects that the deployment has added."),(0,i.kt)("li",{parentName:"ol"},"The builder builds the Docker image for each service concurrently using these projects, building them into the client files as well as copying them so that the api and instanceservers have access to them.\nIf serving client files from the Storage Provider, the client files will be pushed to S3"),(0,i.kt)("li",{parentName:"ol"},"The builder pushes these final Docker images to the repos ",(0,i.kt)("inlineCode",{parentName:"li"},"etherealengine-<release>-<service>")," in ECR (not the client image if serving client files from the Storage Provider)"),(0,i.kt)("li",{parentName:"ol"},"The builder caches all of the layers of each Docker file in S3 for faster build times on subsequent builds"),(0,i.kt)("li",{parentName:"ol"},"The builder updates the main deployment to point to the final images it just created."),(0,i.kt)("li",{parentName:"ol"},"The main deployment spins up the final Docker images for the api, client (optional), instanceserver and taskserver services.")),(0,i.kt)("h2",{id:"install-elastic-search-and-kibana-using-helm-for-server-logs"},"Install Elastic Search and Kibana using Helm for Server Logs"),(0,i.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,i.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,i.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart: "),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,i.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,i.kt)("p",null,"Now check if the cluster members are up: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,i.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,i.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana"),"\nCheck if all the pods are ready: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,i.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"http://localhost:5601 "),"in your browser"),(0,i.kt)("p",null,"In order to connect logger with elasticsearch, update config file(values.yml) for Xr env ",(0,i.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,i.kt)("h3",{id:"upgrading-an-existing-helm-deployment"},"Upgrading an existing Helm deployment"),(0,i.kt)("p",null,"One of the features of Helm is being able to easily upgrade deployments with new values. The command to\ndo this is very similar to the install command:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/*.values.yaml> --set api.image.tag=<latest_github_commit_SHA>,client.image.tag=<latest_github_commit_SHA>,instanceserver.image.tag=<latest_github_commit_SHA> <RELEASE_NAME> etherealengine/etherealengine")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"--reuse-values")," says to carry over all configuration values from the previous deployment. This is most important\nfor tags, since they're usually set inline with the ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install/upgrade")," command, not a Helm config.\nUsing ",(0,i.kt)("inlineCode",{parentName:"p"},"-f <config_file>")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"--set <variables>")," after it will apply any changes on top of the\ncarryover values."),(0,i.kt)("p",null,"If you're not deploying a new build of the codebase, you can skip the entirety of the ",(0,i.kt)("inlineCode",{parentName:"p"},"--set *.image.tag=<SHA>"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/6807199d.393b4448.js b/es/assets/js/6807199d.393b4448.js new file mode 100644 index 000000000000..210e15e71116 --- /dev/null +++ b/es/assets/js/6807199d.393b4448.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[301],{3905:(e,r,t)=>{t.d(r,{Zo:()=>p,kt:()=>m});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function o(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?o(Object(t),!0).forEach((function(r){a(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function i(e,r){if(null==e)return{};var t,n,a=function(e,r){if(null==e)return{};var t,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)t=o[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=n.createContext({}),l=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):c(c({},r),e)),t},p=function(e){var r=l(e.components);return n.createElement(s.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(t),f=a,m=u["".concat(s,".").concat(f)]||u[f]||d[f]||o;return t?n.createElement(m,c(c({ref:r},p),{},{components:t})):n.createElement(m,c({ref:r},p))}));function m(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var o=t.length,c=new Array(o);c[0]=f;var i={};for(var s in r)hasOwnProperty.call(r,s)&&(i[s]=r[s]);i.originalType=e,i[u]="string"==typeof e?e:a,c[1]=i;for(var l=2;l<o;l++)c[l]=t[l];return n.createElement.apply(null,c)}return n.createElement.apply(null,t)}f.displayName="MDXCreateElement"},6364:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>s,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>l});var n=t(7462),a=(t(7294),t(3905));const o={},c=void 0,i={unversionedId:"creator/avatars/readme",id:"creator/avatars/readme",title:"readme",description:"",source:"@site/docs/2_creator/7_avatars/readme.md",sourceDirName:"2_creator/7_avatars",slug:"/creator/avatars/",permalink:"/etherealengine-docs/es/docs/creator/avatars/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/7_avatars/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Debugging Deployed Instanceservers (and other Kubernetes pods)",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers"},next:{title:"Ethereal for Guests",permalink:"/etherealengine-docs/es/docs/guest/"}},s={},l=[],p={toc:l},u="wrapper";function d(e){let{components:r,...t}=e;return(0,a.kt)(u,(0,n.Z)({},p,t,{components:r,mdxType:"MDXLayout"}))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/6945.326f966e.js b/es/assets/js/6945.326f966e.js new file mode 100644 index 000000000000..2a4b1f6ba818 --- /dev/null +++ b/es/assets/js/6945.326f966e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6945],{6945:(e,s,n)=>{n.r(s)}}]); \ No newline at end of file diff --git a/es/assets/js/75750052.b16089c1.js b/es/assets/js/75750052.b16089c1.js new file mode 100644 index 000000000000..7fbb7ad88fa5 --- /dev/null +++ b/es/assets/js/75750052.b16089c1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[532],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>b});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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),g=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=g(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="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,i=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=g(n),p=i,b=u["".concat(s,".").concat(p)]||u[p]||d[p]||o;return n?r.createElement(b,a(a({ref:t},l),{},{components:n})):r.createElement(b,a({ref:t},l))}));function b(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=p;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:i,a[1]=c;for(var g=2;g<o;g++)a[g]=n[g];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},2510:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>g});var r=n(7462),i=(n(7294),n(3905));const o={hide_table_of_contents:!0},a="Debugging",c={unversionedId:"creator/testing/debugging",id:"creator/testing/debugging",title:"Debugging",description:"This section covers different techniques for debugging the source code.",source:"@site/docs/2_creator/6_testing/4_debugging.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/debugging",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/4_debugging.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Writing Good Tests",permalink:"/etherealengine-docs/es/docs/creator/testing/test_driven_development"},next:{title:"Debugging Engine in WSL on Phone/Headset",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl"}},s={},g=[{value:"Basic Debugging",id:"basic-debugging",level:2}],l={toc:g},u="wrapper";function d(e){let{components:t,...o}=e;return(0,i.kt)(u,(0,r.Z)({},l,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"debugging"},"Debugging"),(0,i.kt)("p",null,"This section covers different techniques for debugging the source code."),(0,i.kt)("h2",{id:"basic-debugging"},"Basic Debugging"),(0,i.kt)("p",null,"This config can be used to debug instance server & backend server code. Navigate to 'Run & Debug' tab of vscode."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Add a breakpoint to desired line of code.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Select 'Debug Dev' from debug config dropdown.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Hit the run/play button to start debugging.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Breakpoint will be hit as the code executes that line of code."))),(0,i.kt)("p",null,"Below image further elaborates this."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Basic Debug Image",src:n(8542).Z,width:"1919",height:"960"})))}d.isMDXComponent=!0},8542:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/basic_debug-2e22f14bcb2032b9a1ce61143d3e28a6.png"}}]); \ No newline at end of file diff --git a/es/assets/js/82399a21.c0302048.js b/es/assets/js/82399a21.c0302048.js new file mode 100644 index 000000000000..20f7ba807693 --- /dev/null +++ b/es/assets/js/82399a21.c0302048.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1473],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>g});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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),c=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(o.Provider,{value:t},e.children)},u="mdxType",h={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,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,g=u["".concat(o,".").concat(m)]||u[m]||h[m]||i;return n?a.createElement(g,l(l({ref:t},p),{},{components:n})):a.createElement(g,l({ref:t},p))}));function g(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 s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[u]="string"==typeof e?e:r,l[1]=s;for(var c=2;c<i;c++)l[c]=n[c];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8993:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const i={hide_table_of_contents:!0},l="Unreal Bridge",s={unversionedId:"creator/tutorials/ethereal_engine/unreal_bridge",id:"creator/tutorials/ethereal_engine/unreal_bridge",title:"Unreal Bridge",description:"https://github.com/etherealengine/XRE-Bridge-Unreal",source:"@site/docs/2_creator/5_tutorials/1_ethereal_engine/02_unreal_bridge.md",sourceDirName:"2_creator/5_tutorials/1_ethereal_engine",slug:"/creator/tutorials/ethereal_engine/unreal_bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/1_ethereal_engine/02_unreal_bridge.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Unity Bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge"},next:{title:"Testing",permalink:"/etherealengine-docs/es/docs/creator/testing/"}},o={},c=[{value:"Setup",id:"setup",level:2},{value:"Containerization details",id:"containerization-details",level:3},{value:"Configuring gameserver",id:"configuring-gameserver",level:2},{value:"VaREST and wrapping the Ethereal Engine Web API",id:"varest-and-wrapping-the-ethereal-engine-web-api",level:2},{value:"Open Match Endpoint Reference",id:"open-match-endpoint-reference",level:4}],p={toc:c},u="wrapper";function h(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"unreal-bridge"},"Unreal Bridge"),(0,r.kt)("iframe",{width:"100%",height:"600",src:"https://www.youtube.com/embed/GbOpJRxkux8?&theme=dark&rel=0",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen",allowfullscreen:!0}),(0,r.kt)("h1",{id:"ethereal-engine-bridge---unreal"},"Ethereal Engine Bridge - Unreal"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/XRE-Bridge-Unreal"},"https://github.com/etherealengine/XRE-Bridge-Unreal")),(0,r.kt)("p",null,"Unreal SDK Ethereal Engine Alpha"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"User Management API"),(0,r.kt)("li",{parentName:"ul"},"Server Party Matchmaker"),(0,r.kt)("li",{parentName:"ul"},"Unreal Game Server Lifecycle System"),(0,r.kt)("li",{parentName:"ul"},"Unreal Blueprints Ethereal Engine SDK")),(0,r.kt)("p",null,"CMS and marketplace services coming soon"),(0,r.kt)("p",null,"EXAMPLE ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example"},"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example")),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172299848-3e1c6a5f-ecd2-4562-a894-0d8b55e5b9e5.png",alt:"Screenshot 2022-06-06 193750"})),(0,r.kt)("h2",{id:"setup"},"Setup"),(0,r.kt)("p",null,"This guide assumes you have a working linux dedicated server build of you game."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/HowTo/DedicatedServers/"},"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/HowTo/DedicatedServers/")),(0,r.kt)("li",{parentName:"ul"},"old guides ",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://michaeljcole.github.io/wiki.unrealengine.com/Dedicated_Server_Guide_(Windows_&_Linux)/"},"https://michaeljcole.github.io/wiki.unrealengine.com/Dedicated_Server_Guide_(Windows_&_Linux)/")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://medium.com/swlh/building-and-hosting-an-unreal-engine-dedicated-server-with-aws-and-docker-75317780c567"},"https://medium.com/swlh/building-and-hosting-an-unreal-engine-dedicated-server-with-aws-and-docker-75317780c567"))))),(0,r.kt)("p",null,"Preinstall Requirements"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"VaRest ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/ufna/VaRest"},"https://github.com/ufna/VaRest"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536"},"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536")),(0,r.kt)("li",{parentName:"ul"},"VaREST Tuturials ",(0,r.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=B90jnsEJ6E0"},"https://www.youtube.com/watch?v=B90jnsEJ6E0")))),(0,r.kt)("li",{parentName:"ul"},"Agones SDK w/ Unreal tools ",(0,r.kt)("a",{parentName:"li",href:"https://agones.dev/site/docs/guides/client-sdks/unreal/"},"https://agones.dev/site/docs/guides/client-sdks/unreal/"))),(0,r.kt)("h3",{id:"containerization-details"},"Containerization details"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/dedicated-servers"},"https://unrealcontainers.com/docs/use-cases/dedicated-servers")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/linux-installed-builds"},"https://unrealcontainers.com/docs/use-cases/linux-installed-builds")),(0,r.kt)("li",{parentName:"ul"},"killer advanced use ",(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/pixel-streaming"},"https://unrealcontainers.com/docs/use-cases/pixel-streaming")),(0,r.kt)("li",{parentName:"ul"},"killer advanced use ",(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/continuous-integration"},"https://unrealcontainers.com/docs/use-cases/continuous-integration")),(0,r.kt)("li",{parentName:"ul"},"killer advanced use ",(0,r.kt)("a",{parentName:"li",href:"https://unrealcontainers.com/docs/use-cases/linux-sandboxed-editor"},"https://unrealcontainers.com/docs/use-cases/linux-sandboxed-editor"))),(0,r.kt)("h2",{id:"configuring-gameserver"},"Configuring gameserver"),(0,r.kt)("p",null,"register a process with ENV VARS or Unreal executable arguments"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/CommandLineArguments/"},"https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/CommandLineArguments/")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"TroveServer.exe IslandLobby.uproject /Trove/Maps/Island1?game=MyGameInfo?listen -lobbygame -server 127.0.0.1\nTroveServer.exe IsleOfDeath.uproject /Trove/Maps/IsleOfDeathStart?game=MyGameInfo?listen -stakedgame -server 127.0.0.1\n")),(0,r.kt)("h2",{id:"varest-and-wrapping-the-ethereal-engine-web-api"},"VaREST and wrapping the Ethereal Engine Web API"),(0,r.kt)("p",null,"knowledge required: Learn REST APIs, OpenAPI, Header based http auth, Verbs:Get/Post/etc, paylods, json"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172028597-08e4c4cc-973b-4e4a-924a-1f508dfb4711.png",alt:"image"})),(0,r.kt)("p",null,"Targeting support for 4.26 and 4.27"),(0,r.kt)("p",null,"Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/XRE-Bridge-Unreal/"},"https://github.com/etherealengine/XRE-Bridge-Unreal/")),(0,r.kt)("p",null,"This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine "),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://api-dev.etherealengine.com/openapi/"},"https://api-dev.etherealengine.com/openapi/")),(0,r.kt)("p",null,"This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!"),(0,r.kt)("p",null,"This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database"),(0,r.kt)("img",{width:"1189",alt:"Screen Shot 2022-06-04 at 4 25 43 PM",src:"https://user-images.githubusercontent.com/5104160/172028647-084f7aa0-d358-4b15-b6be-5788ee7d7ec4.png"}),(0,r.kt)("p",null,"Blueprints multiplayer Unreal reference"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/"},"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/")),(0,r.kt)("p",null,"All K8 control plane systems can be access via rest calls to the local network of the gameserver, the functionality of Agones can be done via adding a node in Blueprints."),(0,r.kt)("p",null,"The Ethereal Engine matchmaker service exposes the default endopints for open match."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/01-open-match-core.yaml"},"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/01-open-match-core.yaml"),"\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/07-open-match-default-evaluator.yaml"},"https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/07-open-match-default-evaluator.yaml")),(0,r.kt)("p",null,"REST API local call access docs"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://open-match.dev/site/docs/guides/access/"},"https://open-match.dev/site/docs/guides/access/")),(0,r.kt)("p",null,"This is a ticketing system to be placed into a lobby group and then into a gameserver. Ethereal Engine has API call examples of this"),(0,r.kt)("p",null,"Match User Relation"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-user/match-user.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-user/match-user.class.ts")),(0,r.kt)("h4",{id:"open-match-endpoint-reference"},"Open Match Endpoint Reference"),(0,r.kt)("p",null,"Match the ticket for an assignment"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket/match-ticket.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket/match-ticket.class.ts")),(0,r.kt)("p",null,"Match Gameserver Instance Relation"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-instance/match-instance.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-instance/match-instance.class.ts")),(0,r.kt)("p",null,"Get a ticket for assignment to a gameserver instance"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket-assignment/match-ticket-assignment.class.ts"},"https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket-assignment/match-ticket-assignment.class.ts")),(0,r.kt)("p",null,"Agones Actions"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172027649-676723a1-a5d1-46f0-9406-eb2aa429cf18.png",alt:"unreal_bp_actions"})),(0,r.kt)("h1",{id:"ethereal-engine-bridge-unreal-example"},"Ethereal-Engine-Bridge-Unreal-Example"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example"},"https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example")),(0,r.kt)("p",null,"Preinstall Requirements"),(0,r.kt)("p",null,"Add Plugins"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"From asset store VaRest",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/ufna/VaRest"},"https://github.com/ufna/VaRest")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536"},"https://www.notion.so/VaRest-UE4-Plugin-40b98c54fc184033b60a42e0e4753536")))),(0,r.kt)("li",{parentName:"ul"},"Add agones plugin folder - unreal or project folder",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Agones SDK w/ Unreal tools ",(0,r.kt)("a",{parentName:"li",href:"https://agones.dev/site/docs/guides/client-sdks/unreal/"},"https://agones.dev/site/docs/guides/client-sdks/unreal/"))))),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://user-images.githubusercontent.com/5104160/172296219-06d6d420-7fc4-4981-bf0a-35869768adcd.png",alt:"Screenshot 2022-06-06 193750"})),(0,r.kt)("p",null,"Targeting support for 4.26 and 4.27"),(0,r.kt)("p",null,"Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/etherealengine/XRE-Bridge-Unreal/"},"https://github.com/etherealengine/XRE-Bridge-Unreal/")),(0,r.kt)("p",null,"This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine "),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://api-dev.etherealengine.com/openapi/"},"https://api-dev.etherealengine.com/openapi/")),(0,r.kt)("p",null,"This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!"),(0,r.kt)("p",null,"This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database"),(0,r.kt)("img",{width:"1189",alt:"Screen Shot 2022-06-04 at 4 25 43 PM",src:"https://user-images.githubusercontent.com/5104160/172028647-084f7aa0-d358-4b15-b6be-5788ee7d7ec4.png"}),(0,r.kt)("p",null,"Blueprints multiplayer Unreal reference"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/"},"https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/")),(0,r.kt)("p",null,"Modeled after an updated version of"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://www.unrealengine.com/marketplace/en-US/product/multiplayer-shootout"},"https://www.unrealengine.com/marketplace/en-US/product/multiplayer-shootout"),"\n",(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/Basics/Projects/UIProjectConversion/"},"https://docs.unrealengine.com/4.27/en-US/Basics/Projects/UIProjectConversion/")),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/BlueprintMultiplayer/"},"https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/BlueprintMultiplayer/")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/86c50ec3.231a1b34.js b/es/assets/js/86c50ec3.231a1b34.js new file mode 100644 index 000000000000..7d96aaab6902 --- /dev/null +++ b/es/assets/js/86c50ec3.231a1b34.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8625],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=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 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 l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=c(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,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(n),m=o,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(h,l(l({ref:t},u),{},{components:n})):r.createElement(h,l({ref:t},u))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,l=new Array(a);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,l[1]=i;for(var c=2;c<a;c++)l[c]=n[c];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},183:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={},l="Installing on Mac OS X",i={unversionedId:"host/installation/mac_os_x",id:"host/installation/mac_os_x",title:"Installing on Mac OS X",description:"1. Go to the root and run",source:"@site/docs/1_host/1_installation/2_mac_os_x.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/mac_os_x",permalink:"/etherealengine-docs/es/docs/host/installation/mac_os_x",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/2_mac_os_x.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Basic Setup",permalink:"/etherealengine-docs/es/docs/host/installation/basic_setup"},next:{title:"Installing on Windows 10+",permalink:"/etherealengine-docs/es/docs/host/installation/windows"}},s={},c=[{value:"Troubleshooting Mac",id:"troubleshooting-mac",level:2}],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"installing-on-mac-os-x"},"Installing on Mac OS X"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Go to the root and run")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm install\nnpm run dev-docker\nnpm run dev-reinit\n")),(0,o.kt)("p",null,"Or if you are on a M1 based Mac"),(0,o.kt)("p",null,"(Recommended)\n1) Duplicate the Terminal app, and configure it to run in Rosetta\n2) Run the above in Rosetta Terminal"),(0,o.kt)("p",null,"(Not recommended)"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"yarn install\n")),(0,o.kt)("p",null,"This is because on Apple chips the node-darwin sometimes doesn't get installed\nproperly and by using yarn it fixes the issue."),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"Have docker started in the background and then in the terminal type")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm run dev\n")),(0,o.kt)("p",null,"This will open the mariaDB and SQL scripts on the docker and will start the servers"),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"To make sure your environment is set and running properly just go to\nhttps://localhost:3000/location/default and you should be able to walk around an empty 3D scene")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Note : Make sure you are on Node >= 16 and have docker running. \n")),(0,o.kt)("h2",{id:"troubleshooting-mac"},"Troubleshooting Mac"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"If you find issues on your terminal that says that access-denied for user\n",(0,o.kt)("inlineCode",{parentName:"li"},"server@localhost")," then you can use this command")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"brew services stop mysql\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"If you find issue on your terminal that says\n",(0,o.kt)("inlineCode",{parentName:"li"},'An unexpected error occurred: "expected workspace package'),"\nwhile using yarn then you can use this command in your terminal")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"yarn policies set-version 1.18.0\n")),(0,o.kt)("p",null,"As yarn > 1.18 sometimes doesn't work properly with lerna."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/8894.2c471ab3.js b/es/assets/js/8894.2c471ab3.js new file mode 100644 index 000000000000..c5ca8fc43b4d --- /dev/null +++ b/es/assets/js/8894.2c471ab3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8894],{8894:(e,s,n)=>{n.r(s)}}]); \ No newline at end of file diff --git a/es/assets/js/8df89772.b7fc7bc7.js b/es/assets/js/8df89772.b7fc7bc7.js new file mode 100644 index 000000000000..321e2a2a271a --- /dev/null +++ b/es/assets/js/8df89772.b7fc7bc7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8620],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var n=r(7294);function o(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 l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function a(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=a(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return r?n.createElement(f,l(l({ref:t},c),{},{components:r})):n.createElement(f,l({ref:t},c))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,l=new Array(i);l[0]=m;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a[u]="string"==typeof e?e:o,l[1]=a;for(var p=2;p<i;p++)l[p]=r[p];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},4085:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>a,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const i={},l="Asset Import Pipeline",a={unversionedId:"creator/importing_assets/readme",id:"creator/importing_assets/readme",title:"Asset Import Pipeline",description:"WARNING: This page is out of date",source:"@site/docs/2_creator/3_importing_assets/readme.md",sourceDirName:"2_creator/3_importing_assets",slug:"/creator/importing_assets/",permalink:"/etherealengine-docs/es/docs/creator/importing_assets/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/3_importing_assets/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Studio Overview",permalink:"/etherealengine-docs/es/docs/creator/studio/"},next:{title:"Development",permalink:"/etherealengine-docs/es/docs/creator/development/"}},s={},p=[{value:"WARNING: This page is out of date",id:"warning-this-page-is-out-of-date",level:2},{value:"Collider Metadata",id:"collider-metadata",level:2}],c={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"asset-import-pipeline"},"Asset Import Pipeline"),(0,o.kt)("h1",{id:"omniverse"},"Omniverse"),(0,o.kt)("h1",{id:"unity"},"Unity"),(0,o.kt)("h1",{id:"unreal"},"Unreal"),(0,o.kt)("h1",{id:"blender"},"Blender"),(0,o.kt)("h2",{id:"warning-this-page-is-out-of-date"},"WARNING: This page is out of date"),(0,o.kt)("p",null,"The simplest pipeline uses Blender & the Studio's inbuilt transformation tool. "),(0,o.kt)("p",null,"Scenes that contain colliders should have these colliders exported separately.\nVisible meshes should not have collider metadata, instead a copy should be created."),(0,o.kt)("p",null,"The process of moving from Blender to Ethereal Engine looks like the following:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Blend file is the source of truth"),(0,o.kt)("li",{parentName:"ol"},"Export visible meshes from from blend file"),(0,o.kt)("li",{parentName:"ol"},"Export collider meshes from blend file with Custom Properties"),(0,o.kt)("li",{parentName:"ol"},"Import to editor"),(0,o.kt)("li",{parentName:"ol"},"Optimize visible glb with transformation tool"),(0,o.kt)("li",{parentName:"ol"},"Use final transformed visible glb & collider glb for live scene")),(0,o.kt)("h2",{id:"collider-metadata"},"Collider Metadata"),(0,o.kt)("p",null,"All fixed colliders should be a child of a separate root hierarchy."),(0,o.kt)("p",null,"The root object of the collider hiearchy must have ",(0,o.kt)("inlineCode",{parentName:"p"},"xrengine.collider.bodyType: Fixed"),"\nEach collider must be a child of the root object with ",(0,o.kt)("inlineCode",{parentName:"p"},"shapeType: <shape>")),(0,o.kt)("p",null,"The currently supported shapes are as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Cuboid"),(0,o.kt)("li",{parentName:"ul"},"Ball"),(0,o.kt)("li",{parentName:"ul"},"Capsule"),(0,o.kt)("li",{parentName:"ul"},"Cylinder"),(0,o.kt)("li",{parentName:"ul"},"ConvexPolyhedron"),(0,o.kt)("li",{parentName:"ul"},"TriMesh")),(0,o.kt)("p",null,"Other supported metadata for each collider is:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"friction: number"),(0,o.kt)("li",{parentName:"ul"},"restitution number"),(0,o.kt)("li",{parentName:"ul"},"collisionLayer: number"),(0,o.kt)("li",{parentName:"ul"},"collisionMask: number"),(0,o.kt)("li",{parentName:"ul"},"isTrigger: number")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/917fb754.32092b78.js b/es/assets/js/917fb754.32092b78.js new file mode 100644 index 000000000000..a031ddb1cdd6 --- /dev/null +++ b/es/assets/js/917fb754.32092b78.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[7053],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={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,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(r),f=o,m=p["".concat(l,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},2018:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={},i="Tutorials",c={unversionedId:"creator/tutorials/readme",id:"creator/tutorials/readme",title:"Tutorials",description:"In this section you will various tutorials for Ethereal Engine and its ecosystem.",source:"@site/docs/2_creator/5_tutorials/readme.md",sourceDirName:"2_creator/5_tutorials",slug:"/creator/tutorials/",permalink:"/etherealengine-docs/es/docs/creator/tutorials/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/5_tutorials/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Introduction",permalink:"/etherealengine-docs/es/docs/creator/development/behave_graph"},next:{title:"Ethereal Engine",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/"}},l={},s=[],u={toc:s},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"tutorials"},"Tutorials"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine and its ecosystem."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/935f2afb.eeb7911d.js b/es/assets/js/935f2afb.eeb7911d.js new file mode 100644 index 000000000000..2f20ba0ab9f0 --- /dev/null +++ b/es/assets/js/935f2afb.eeb7911d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).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":"Overview","href":"/etherealengine-docs/es/docs/","docId":"overview"},{"type":"category","label":"Ethereal for Hosts","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Installation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Basic Setup","href":"/etherealengine-docs/es/docs/host/installation/basic_setup","docId":"host/installation/basic_setup"},{"type":"link","label":"Installing on Mac OS X","href":"/etherealengine-docs/es/docs/host/installation/mac_os_x","docId":"host/installation/mac_os_x"},{"type":"link","label":"Installing on Windows 10+","href":"/etherealengine-docs/es/docs/host/installation/windows","docId":"host/installation/windows"},{"type":"link","label":"Installing on Windows with WSL2","href":"/etherealengine-docs/es/docs/host/installation/windows_wsl","docId":"host/installation/windows_wsl"},{"type":"link","label":"Advanced Setup","href":"/etherealengine-docs/es/docs/host/installation/advanced_setup","docId":"host/installation/advanced_setup"},{"type":"link","label":"Running on Static IP under WSL2","href":"/etherealengine-docs/es/docs/host/installation/running_on_static_IP","docId":"host/installation/running_on_static_IP"},{"type":"link","label":"Troubleshooting","href":"/etherealengine-docs/es/docs/host/installation/install_troubleshooting","docId":"host/installation/install_troubleshooting"},{"type":"link","label":"Old Docker Instructions","href":"/etherealengine-docs/es/docs/host/installation/docker","docId":"host/installation/docker"},{"type":"link","label":"Logging with Opensearch on Docker","href":"/etherealengine-docs/es/docs/host/installation/opensearch","docId":"host/installation/opensearch"}],"href":"/etherealengine-docs/es/docs/host/installation/"},{"type":"category","label":"Deployment","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Ethereal Engine on MicroK8s (Linux)","href":"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux","docId":"host/devops_deployment/microk8s_linux"},{"type":"link","label":"Ethereal Engine on MicroK8s (Windows)","href":"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows","docId":"host/devops_deployment/microk8s_windows"},{"type":"link","label":"Ethereal Engine on Docker Desktop","href":"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop","docId":"host/devops_deployment/docker_desktop"},{"type":"link","label":"Ethereal Engine on Minikube","href":"/etherealengine-docs/es/docs/host/devops_deployment/minikube","docId":"host/devops_deployment/minikube"},{"type":"link","label":"Ethereal Engine on AWS","href":"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup","docId":"host/devops_deployment/AWS_setup"},{"type":"link","label":"Installing Projects","href":"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects","docId":"host/devops_deployment/installing_projects"},{"type":"link","label":"Database Migrations","href":"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations","docId":"host/devops_deployment/database_migrations"},{"type":"link","label":"How to set up GitHub to install external projects","href":"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects","docId":"host/devops_deployment/setup_github_oauth_for_projects"},{"type":"link","label":"Cluster Management","href":"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes","docId":"host/devops_deployment/managing_remote_kubernetes"},{"type":"link","label":"Release Helm Chart","href":"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart","docId":"host/devops_deployment/release_helm_chart"},{"type":"link","label":"Upgrading Helm Release","href":"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment","docId":"host/devops_deployment/upgrade_helm_deployment"},{"type":"category","label":"Tutorials","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Control Center App","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started","docId":"host/devops_deployment/tutorials/ethereal_control_center/getting_started"}],"href":"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/"}],"href":"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/"}],"href":"/etherealengine-docs/es/docs/host/devops_deployment/"},{"type":"link","label":"Ethereal Engine Admin Panel Guide","href":"/etherealengine-docs/es/docs/host/Admin_Dashboard/","docId":"host/Admin_Dashboard/readme"}],"href":"/etherealengine-docs/es/docs/host/"},{"type":"category","label":"Ethereal for Creators","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Concepts","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Studio & Locations","href":"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations","docId":"creator/concepts/editor_scenes_locations"}],"href":"/etherealengine-docs/es/docs/creator/concepts/"},{"type":"link","label":"Studio Overview","href":"/etherealengine-docs/es/docs/creator/studio/","docId":"creator/studio/readme"},{"type":"link","label":"Asset Import Pipeline","href":"/etherealengine-docs/es/docs/creator/importing_assets/","docId":"creator/importing_assets/readme"},{"type":"category","label":"Development","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Projects","href":"/etherealengine-docs/es/docs/creator/development/projects_overview","docId":"creator/development/projects_overview"},{"type":"link","label":"State Management","href":"/etherealengine-docs/es/docs/creator/development/state_management","docId":"creator/development/state_management"},{"type":"link","label":"Entities, Components and Systems","href":"/etherealengine-docs/es/docs/creator/development/ecs","docId":"creator/development/ecs"},{"type":"link","label":"Networking","href":"/etherealengine-docs/es/docs/creator/development/networking","docId":"creator/development/networking"},{"type":"link","label":"Event Sourcing","href":"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing","docId":"creator/development/actions_event_sourcing"},{"type":"link","label":"Introduction","href":"/etherealengine-docs/es/docs/creator/development/behave_graph","docId":"creator/development/behave_graph"}],"href":"/etherealengine-docs/es/docs/creator/development/"},{"type":"category","label":"Tutorials","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Ethereal Engine","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Unity Bridge","href":"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge","docId":"creator/tutorials/ethereal_engine/unity_bridge"},{"type":"link","label":"Unreal Bridge","href":"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge","docId":"creator/tutorials/ethereal_engine/unreal_bridge"}],"href":"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/"}],"href":"/etherealengine-docs/es/docs/creator/tutorials/"},{"type":"category","label":"Testing","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Testing Basics","href":"/etherealengine-docs/es/docs/creator/testing/testing_intro","docId":"creator/testing/testing_intro"},{"type":"link","label":"Writing Reasonable & Testable Code","href":"/etherealengine-docs/es/docs/creator/testing/reasonable_code","docId":"creator/testing/reasonable_code"},{"type":"link","label":"Writing Good Tests","href":"/etherealengine-docs/es/docs/creator/testing/test_driven_development","docId":"creator/testing/test_driven_development"},{"type":"link","label":"Debugging","href":"/etherealengine-docs/es/docs/creator/testing/debugging","docId":"creator/testing/debugging"},{"type":"link","label":"Debugging Engine in WSL on Phone/Headset","href":"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl","docId":"creator/testing/debugging_device_wsl"},{"type":"link","label":"Debugging Deployed Instanceservers (and other Kubernetes pods)","href":"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers","docId":"creator/testing/debugging_deployed_instanceservers"}],"href":"/etherealengine-docs/es/docs/creator/testing/"},{"type":"link","label":"readme","href":"/etherealengine-docs/es/docs/creator/avatars/","docId":"creator/avatars/readme"}],"href":"/etherealengine-docs/es/docs/creator/"},{"type":"link","label":"Ethereal for Guests","href":"/etherealengine-docs/es/docs/guest/","docId":"guest/readme"}]},"docs":{"creator/avatars/readme":{"id":"creator/avatars/readme","title":"readme","description":"","sidebar":"tutorialSidebar"},"creator/concepts/editor_scenes_locations":{"id":"creator/concepts/editor_scenes_locations","title":"Studio & Locations","description":"Scene Studio","sidebar":"tutorialSidebar"},"creator/concepts/readme":{"id":"creator/concepts/readme","title":"Concepts","description":"","sidebar":"tutorialSidebar"},"creator/development/actions_event_sourcing":{"id":"creator/development/actions_event_sourcing","title":"Event Sourcing","description":"Actions","sidebar":"tutorialSidebar"},"creator/development/behave_graph":{"id":"creator/development/behave_graph","title":"Introduction","description":"* Overview","sidebar":"tutorialSidebar"},"creator/development/ecs":{"id":"creator/development/ecs","title":"Entities, Components and Systems","description":"What is an ECS?","sidebar":"tutorialSidebar"},"creator/development/networking":{"id":"creator/development/networking","title":"Networking","description":"Networks","sidebar":"tutorialSidebar"},"creator/development/projects_overview":{"id":"creator/development/projects_overview","title":"Projects","description":"Projects are folders that contain all your custom code, assets and scenes. They","sidebar":"tutorialSidebar"},"creator/development/readme":{"id":"creator/development/readme","title":"Development","description":"In this section you will find out how to create your own projects with Ethereal Engine.","sidebar":"tutorialSidebar"},"creator/development/state_management":{"id":"creator/development/state_management","title":"State Management","description":"All of Ethereal Engine\'s state management uses hookstate and react. Together, these tools give reactive, declarative, and controlled state management across any scope.","sidebar":"tutorialSidebar"},"creator/importing_assets/readme":{"id":"creator/importing_assets/readme","title":"Asset Import Pipeline","description":"WARNING: This page is out of date","sidebar":"tutorialSidebar"},"creator/readme":{"id":"creator/readme","title":"Ethereal for Creators","description":"Learn how to create, code and customize projects with Ethereal Engine","sidebar":"tutorialSidebar"},"creator/studio/readme":{"id":"creator/studio/readme","title":"Studio Overview","description":"Ethereal Engine Studio","sidebar":"tutorialSidebar"},"creator/testing/debugging":{"id":"creator/testing/debugging","title":"Debugging","description":"This section covers different techniques for debugging the source code.","sidebar":"tutorialSidebar"},"creator/testing/debugging_deployed_instanceservers":{"id":"creator/testing/debugging_deployed_instanceservers","title":"Debugging Deployed Instanceservers (and other Kubernetes pods)","description":"Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear","sidebar":"tutorialSidebar"},"creator/testing/debugging_device_wsl":{"id":"creator/testing/debugging_device_wsl","title":"Debugging Engine in WSL on Phone/Headset","description":"This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11.","sidebar":"tutorialSidebar"},"creator/testing/readme":{"id":"creator/testing/readme","title":"Testing","description":"Automated testing is a cornerstone to successful software development. Tests are","sidebar":"tutorialSidebar"},"creator/testing/reasonable_code":{"id":"creator/testing/reasonable_code","title":"Writing Reasonable & Testable Code","description":"Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application.","sidebar":"tutorialSidebar"},"creator/testing/test_driven_development":{"id":"creator/testing/test_driven_development","title":"Writing Good Tests","description":"Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:","sidebar":"tutorialSidebar"},"creator/testing/testing_intro":{"id":"creator/testing/testing_intro","title":"Testing Basics","description":"","sidebar":"tutorialSidebar"},"creator/tutorials/ethereal_engine/readme":{"id":"creator/tutorials/ethereal_engine/readme","title":"Ethereal Engine","description":"In this section you will various tutorials for Ethereal Engine.","sidebar":"tutorialSidebar"},"creator/tutorials/ethereal_engine/unity_bridge":{"id":"creator/tutorials/ethereal_engine/unity_bridge","title":"Unity Bridge","description":"","sidebar":"tutorialSidebar"},"creator/tutorials/ethereal_engine/unreal_bridge":{"id":"creator/tutorials/ethereal_engine/unreal_bridge","title":"Unreal Bridge","description":"https://github.com/etherealengine/XRE-Bridge-Unreal","sidebar":"tutorialSidebar"},"creator/tutorials/readme":{"id":"creator/tutorials/readme","title":"Tutorials","description":"In this section you will various tutorials for Ethereal Engine and its ecosystem.","sidebar":"tutorialSidebar"},"guest/readme":{"id":"guest/readme","title":"Ethereal for Guests","description":"Whether you\'re a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine.","sidebar":"tutorialSidebar"},"host/Admin_Dashboard/readme":{"id":"host/Admin_Dashboard/readme","title":"Ethereal Engine Admin Panel Guide","description":"Dashboard","sidebar":"tutorialSidebar"},"host/devops_deployment/AWS_setup":{"id":"host/devops_deployment/AWS_setup","title":"Ethereal Engine on AWS","description":"The value RELEASE_NAME referenced throughout this guide is the name of the deployment, e.g. dev or prod.","sidebar":"tutorialSidebar"},"host/devops_deployment/database_migrations":{"id":"host/devops_deployment/database_migrations","title":"Database Migrations","description":"Create Migration File","sidebar":"tutorialSidebar"},"host/devops_deployment/docker_desktop":{"id":"host/devops_deployment/docker_desktop","title":"Ethereal Engine on Docker Desktop","description":"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.","sidebar":"tutorialSidebar"},"host/devops_deployment/installing_projects":{"id":"host/devops_deployment/installing_projects","title":"Installing Projects","description":"Local Install Flow","sidebar":"tutorialSidebar"},"host/devops_deployment/managing_remote_kubernetes":{"id":"host/devops_deployment/managing_remote_kubernetes","title":"Cluster Management","description":"Kubernetes Web UI (Dashboard)","sidebar":"tutorialSidebar"},"host/devops_deployment/microk8s_linux":{"id":"host/devops_deployment/microk8s_linux","title":"Ethereal Engine on MicroK8s (Linux)","description":"This guide is intended for local environment and currently tested on Ubuntu.","sidebar":"tutorialSidebar"},"host/devops_deployment/microk8s_windows":{"id":"host/devops_deployment/microk8s_windows","title":"Ethereal Engine on MicroK8s (Windows)","description":"This guide is intended for local environment and currently tested on Windows 11.","sidebar":"tutorialSidebar"},"host/devops_deployment/minikube":{"id":"host/devops_deployment/minikube","title":"Ethereal Engine on Minikube","description":"Install kubectl, Helm, Docker, and VirtualBox","sidebar":"tutorialSidebar"},"host/devops_deployment/readme":{"id":"host/devops_deployment/readme","title":"Deployment","description":"In this section you will find out how to deploy Ethereal Engine.","sidebar":"tutorialSidebar"},"host/devops_deployment/release_helm_chart":{"id":"host/devops_deployment/release_helm_chart","title":"Release Helm Chart","description":"Following are the steps that needs to be taken in order to update etherealengine helm charts repo:","sidebar":"tutorialSidebar"},"host/devops_deployment/setup_github_oauth_for_projects":{"id":"host/devops_deployment/setup_github_oauth_for_projects","title":"How to set up GitHub to install external projects","description":"Ethereal Engine is extensible via Projects, which can contain","sidebar":"tutorialSidebar"},"host/devops_deployment/tutorials/ethereal_control_center/getting_started":{"id":"host/devops_deployment/tutorials/ethereal_control_center/getting_started","title":"Getting Started","description":"The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster.","sidebar":"tutorialSidebar"},"host/devops_deployment/tutorials/ethereal_control_center/readme":{"id":"host/devops_deployment/tutorials/ethereal_control_center/readme","title":"Control Center App","description":"In this section you will various tutorials for Ethereal Engine Control System app.","sidebar":"tutorialSidebar"},"host/devops_deployment/tutorials/readme":{"id":"host/devops_deployment/tutorials/readme","title":"Tutorials","description":"In this section you will various tutorials for Ethereal Engine and its hosting techniques.","sidebar":"tutorialSidebar"},"host/devops_deployment/upgrade_helm_deployment":{"id":"host/devops_deployment/upgrade_helm_deployment","title":"Upgrading Helm Release","description":"This guide will cover various sections regarding upgrading an existing helm deployment.","sidebar":"tutorialSidebar"},"host/installation/advanced_setup":{"id":"host/installation/advanced_setup","title":"Advanced Setup","description":"If you want to setup Ethereal Engine docker instances, client, server, and/or","sidebar":"tutorialSidebar"},"host/installation/basic_setup":{"id":"host/installation/basic_setup","title":"Basic Setup","description":"","sidebar":"tutorialSidebar"},"host/installation/docker":{"id":"host/installation/docker","title":"Old Docker Instructions","description":"You can quickstart locally using docker, if you don\'t have node installed or","sidebar":"tutorialSidebar"},"host/installation/install_troubleshooting":{"id":"host/installation/install_troubleshooting","title":"Troubleshooting","description":"Browser Debug","sidebar":"tutorialSidebar"},"host/installation/mac_os_x":{"id":"host/installation/mac_os_x","title":"Installing on Mac OS X","description":"1. Go to the root and run","sidebar":"tutorialSidebar"},"host/installation/opensearch":{"id":"host/installation/opensearch","title":"Logging with Opensearch on Docker","description":"If you want to quickstart with detailed logging using opensearch, Please follow this guide.","sidebar":"tutorialSidebar"},"host/installation/readme":{"id":"host/installation/readme","title":"Installation","description":"Getting up and running requires just a few steps, but this can be tricky,","sidebar":"tutorialSidebar"},"host/installation/running_on_static_IP":{"id":"host/installation/running_on_static_IP","title":"Running on Static IP under WSL2","description":"Follow these steps to run the engine on a static IP instead of localhost. In","sidebar":"tutorialSidebar"},"host/installation/windows":{"id":"host/installation/windows","title":"Installing on Windows 10+","description":"1. Install python 3 and add python installation directory path to \'PATH\' env variable.","sidebar":"tutorialSidebar"},"host/installation/windows_wsl":{"id":"host/installation/windows_wsl","title":"Installing on Windows with WSL2","description":"This guide is currently tested on Windows 10 (22H2) and Windows 11.","sidebar":"tutorialSidebar"},"host/readme":{"id":"host/readme","title":"Ethereal for Hosts","description":"Learn how to host your own Ethereal Engine deployment","sidebar":"tutorialSidebar"},"overview":{"id":"overview","title":"Overview","description":"Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/es/assets/js/95bfc3a6.66363db1.js b/es/assets/js/95bfc3a6.66363db1.js new file mode 100644 index 000000000000..ae75d3d046c5 --- /dev/null +++ b/es/assets/js/95bfc3a6.66363db1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5459],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(r),m=o,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:o,i[1]=l;for(var c=2;c<a;c++)i[c]=r[c];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},9702:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=r(7462),o=(r(7294),r(3905));const a={},i="Tutorials",l={unversionedId:"host/devops_deployment/tutorials/readme",id:"host/devops_deployment/tutorials/readme",title:"Tutorials",description:"In this section you will various tutorials for Ethereal Engine and its hosting techniques.",source:"@site/docs/1_host/2_devops_deployment/8_tutorials/readme.md",sourceDirName:"1_host/2_devops_deployment/8_tutorials",slug:"/host/devops_deployment/tutorials/",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/8_tutorials/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Upgrading Helm Release",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment"},next:{title:"Control Center App",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/"}},s={},c=[],p={toc:c},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"tutorials"},"Tutorials"),(0,o.kt)("p",null,"In this section you will various tutorials for Ethereal Engine and its hosting techniques."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/9a2a3fee.536081b5.js b/es/assets/js/9a2a3fee.536081b5.js new file mode 100644 index 000000000000..0f5153ca2709 --- /dev/null +++ b/es/assets/js/9a2a3fee.536081b5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5229],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var r=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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(n),u=o,g=d["".concat(s,".").concat(u)]||d[u]||m[u]||a;return n?r.createElement(g,i(i({ref:t},c),{},{components:n})):r.createElement(g,i({ref:t},c))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var p=2;p<a;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3901:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const a={},i="Database Migrations",l={unversionedId:"host/devops_deployment/database_migrations",id:"host/devops_deployment/database_migrations",title:"Database Migrations",description:"Create Migration File",source:"@site/docs/1_host/2_devops_deployment/3_database_migrations.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/database_migrations",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/3_database_migrations.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing Projects",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects"},next:{title:"How to set up GitHub to install external projects",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects"}},s={},p=[{value:"Create Migration File",id:"create-migration-file",level:2},{value:"OpenAPI",id:"openapi",level:2}],c={toc:p},d="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"database-migrations"},"Database Migrations"),(0,o.kt)("h2",{id:"create-migration-file"},"Create Migration File"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"In your ethereal engine repo run following command")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," cd packages/server-core\n")),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"Afterward run following command to generate migration file: ",(0,o.kt)("inlineCode",{parentName:"li"},"TIMESTAMP_NAME.ts")," i.e. ",(0,o.kt)("inlineCode",{parentName:"li"},"20230418102549_eks-column.ts")," in ",(0,o.kt)("inlineCode",{parentName:"li"},"server-core")," folder.")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," npm run migrate:make -- {NAME}\n")),(0,o.kt)("p",null,"i.e."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," npm run migrate:make -- eks-column\n")),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"Move the migration file to your service's ",(0,o.kt)("inlineCode",{parentName:"li"},"migrations")," folder. i.e. ",(0,o.kt)("inlineCode",{parentName:"li"},"packages/server-core/src/setting/aws-setting/migrations")),(0,o.kt)("li",{parentName:"ol"},"Update that file with code to match your needs.")),(0,o.kt)("h2",{id:"openapi"},"OpenAPI"),(0,o.kt)("p",null,"Our server is set up with Swagger documentation to automatically generate from most endpoints. A few custom routes are not documented at this time, but most of the basic stuff is."),(0,o.kt)("p",null,"You can see the docs for a running Ethereal Engine instance locally at:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"https://localhost:3030/openapi\n")),(0,o.kt)("p",null,"Or on our ",(0,o.kt)("a",{parentName:"p",href:"https://api-dev.etherealengine.com/openapi"},"dev cluster")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/a1c60d7a.7ce3e8be.js b/es/assets/js/a1c60d7a.7ce3e8be.js new file mode 100644 index 000000000000..4b24a8c63be1 --- /dev/null +++ b/es/assets/js/a1c60d7a.7ce3e8be.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8949],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=l(r),h=o,d=p["".concat(c,".").concat(h)]||p[h]||f[h]||a;return r?n.createElement(d,s(s({ref:t},u),{},{components:r})):n.createElement(d,s({ref:t},u))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:o,s[1]=i;for(var l=2;l<a;l++)s[l]=r[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}h.displayName="MDXCreateElement"},1144:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>f,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={},s="Ethereal for Guests",i={unversionedId:"guest/readme",id:"guest/readme",title:"Ethereal for Guests",description:"Whether you're a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine.",source:"@site/docs/3_guest/readme.md",sourceDirName:"3_guest",slug:"/guest/",permalink:"/etherealengine-docs/es/docs/guest/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/3_guest/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"readme",permalink:"/etherealengine-docs/es/docs/creator/avatars/"}},c={},l=[],u={toc:l},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-for-guests"},"Ethereal for Guests"),(0,o.kt)("p",null,"Whether you're a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/a47a1e93.831bfca6.js b/es/assets/js/a47a1e93.831bfca6.js new file mode 100644 index 000000000000..8b2425c861c2 --- /dev/null +++ b/es/assets/js/a47a1e93.831bfca6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5992,2130],{3905:(t,e,n)=>{n.d(e,{Zo:()=>c,kt:()=>m});var r=n(7294);function s(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function a(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function i(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?a(Object(n),!0).forEach((function(e){s(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function o(t,e){if(null==t)return{};var n,r,s=function(t,e){if(null==t)return{};var n,r,s={},a=Object.keys(t);for(r=0;r<a.length;r++)n=a[r],e.indexOf(n)>=0||(s[n]=t[n]);return s}(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(r=0;r<a.length;r++)n=a[r],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(s[n]=t[n])}return s}var l=r.createContext({}),d=function(t){var e=r.useContext(l),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},c=function(t){var e=d(t.components);return r.createElement(l.Provider,{value:e},t.children)},g="mdxType",p={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},u=r.forwardRef((function(t,e){var n=t.components,s=t.mdxType,a=t.originalType,l=t.parentName,c=o(t,["components","mdxType","originalType","parentName"]),g=d(n),u=s,m=g["".concat(l,".").concat(u)]||g[u]||p[u]||a;return n?r.createElement(m,i(i({ref:e},c),{},{components:n})):r.createElement(m,i({ref:e},c))}));function m(t,e){var n=arguments,s=e&&e.mdxType;if("string"==typeof t||s){var a=n.length,i=new Array(a);i[0]=u;var o={};for(var l in e)hasOwnProperty.call(e,l)&&(o[l]=e[l]);o.originalType=t,o[g]="string"==typeof t?t:s,i[1]=o;for(var d=2;d<a;d++)i[d]=n[d];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},7878:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>d,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var r=n(7462),s=(n(7294),n(3905)),a=n(496);const i={},o="Testing Basics",l={unversionedId:"creator/testing/testing_intro",id:"creator/testing/testing_intro",title:"Testing Basics",description:"",source:"@site/docs/2_creator/6_testing/1_testing_intro.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/testing_intro",permalink:"/etherealengine-docs/es/docs/creator/testing/testing_intro",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/1_testing_intro.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Testing",permalink:"/etherealengine-docs/es/docs/creator/testing/"},next:{title:"Writing Reasonable & Testable Code",permalink:"/etherealengine-docs/es/docs/creator/testing/reasonable_code"}},d={},c=[],g={toc:c},p="wrapper";function u(t){let{components:e,...n}=t;return(0,s.kt)(p,(0,r.Z)({},g,n,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"testing-basics"},"Testing Basics"),(0,s.kt)(a.default,{mdxType:"Readme"}))}u.isMDXComponent=!0},496:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>o,toc:()=>d});var r=n(7462),s=(n(7294),n(3905));const a={},i="Testing",o={unversionedId:"creator/testing/readme",id:"creator/testing/readme",title:"Testing",description:"Automated testing is a cornerstone to successful software development. Tests are",source:"@site/docs/2_creator/6_testing/readme.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/",permalink:"/etherealengine-docs/es/docs/creator/testing/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Unreal Bridge",permalink:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge"},next:{title:"Testing Basics",permalink:"/etherealengine-docs/es/docs/creator/testing/testing_intro"}},l={},d=[{value:"SMTP Testing",id:"smtp-testing",level:2},{value:"Unit tests",id:"unit-tests",level:2},{value:"Integration tests",id:"integration-tests",level:2},{value:"Unit vs Integration Tests (source)",id:"unit-vs-integration-tests-source",level:2},{value:"System tests",id:"system-tests",level:2},{value:"End-to-end tests",id:"end-to-end-tests",level:2},{value:"System vs End-to-end Tests (source)",id:"system-vs-end-to-end-tests-source",level:2},{value:"White-box vs Black-box testing",id:"white-box-vs-black-box-testing",level:2},{value:"The Testing Pyramid",id:"the-testing-pyramid",level:2}],c={toc:d},g="wrapper";function p(t){let{components:e,...n}=t;return(0,s.kt)(g,(0,r.Z)({},c,n,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"testing"},"Testing"),(0,s.kt)("p",null,"Automated testing is a cornerstone to successful software development. Tests are\nnot just to ensure that your application is working as intended, they are also\nto ensure that ",(0,s.kt)("strong",{parentName:"p"},"existing features aren't broken by any newly introduced features\nor code"),", aka ",(0,s.kt)("strong",{parentName:"p"},"regression bugs"),". The latter tends to hold more value, as it\nmakes the software sturdy and less prone to these types of bugs during active\ndevelopment of a project. Regression bugs will quickly stall the development of\na project at a certain level of complexity, effectively preventing progress."),(0,s.kt)("h2",{id:"smtp-testing"},"SMTP Testing"),(0,s.kt)("p",null,(0,s.kt)("a",{parentName:"p",href:"https://mailtrap.io/inboxes"},"https://mailtrap.io/inboxes")),(0,s.kt)("p",null,"Add credentials in ",(0,s.kt)("inlineCode",{parentName:"p"},".env.local")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-dotenv"},"SMTP_HOST=smtp.mailtrap.io\nSMTP_PORT=2525\nSMTP_USER=<mailtrap-user>\nSMTP_PASS=<mailtrap-password>\n")),(0,s.kt)("h2",{id:"unit-tests"},"Unit tests"),(0,s.kt)("p",null,"Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-js"},"const add2 = x => x + 2\n\nit('should add 2 to a given number', () => {\n strictEqual(add2(1), 3)\n})\n")),(0,s.kt)("h2",{id:"integration-tests"},"Integration tests"),(0,s.kt)("p",null,"Integration tests focus on testing bundles of code units. A composition of functions, for example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-js"},"const addTwo = x => x + 2\nconst multThree = x => x * 3\nconst halve = x => x / 2\n\nconst algorithm = x => {\n x = addTwo(x)\n x = multThree(x)\n x = halve(x)\n return x\n}\n\nit('should apply the entire algorithm correctly', () => {\n strictEqual(algorithm(4), 9)\n})\n")),(0,s.kt)("h2",{id:"unit-vs-integration-tests-source"},"Unit vs Integration Tests (",(0,s.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-unit-testing-and-integration-testing/"},"source"),")"),(0,s.kt)("table",null,(0,s.kt)("thead",{parentName:"table"},(0,s.kt)("tr",{parentName:"thead"},(0,s.kt)("th",{parentName:"tr",align:null},"Unit Testing"),(0,s.kt)("th",{parentName:"tr",align:null},"Integration Testing"))),(0,s.kt)("tbody",{parentName:"table"},(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"In unit testing each module of the software is tested separately."),(0,s.kt)("td",{parentName:"tr",align:null},"In integration testing all modules of the the software are tested combined.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"In unit testing the tester knows the internal design of the software."),(0,s.kt)("td",{parentName:"tr",align:null},"In integration testing the tester doesn't know the internal design of the software.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"Unit testing is performed first of all testing processes."),(0,s.kt)("td",{parentName:"tr",align:null},"Integration testing is performed after unit testing, and before system/end-to-end tests.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"Unit testing is a white box testing."),(0,s.kt)("td",{parentName:"tr",align:null},"Integration testing is a black box testing.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"Unit testing is performed by the developer."),(0,s.kt)("td",{parentName:"tr",align:null},"Integration testing is performed by the tester.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"Detection of defects in unit testing is easy."),(0,s.kt)("td",{parentName:"tr",align:null},"Detection of defects in integration testing is difficult.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"It tests parts of the project without waiting for others to be completed."),(0,s.kt)("td",{parentName:"tr",align:null},"It tests only after the completion of all parts.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"Unit testing is less costly."),(0,s.kt)("td",{parentName:"tr",align:null},"Integration testing is more costly.")))),(0,s.kt)("h2",{id:"system-tests"},"System tests"),(0,s.kt)("p",null,"System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test)."),(0,s.kt)("h2",{id:"end-to-end-tests"},"End-to-end tests"),(0,s.kt)("p",null,"End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow)."),(0,s.kt)("h2",{id:"system-vs-end-to-end-tests-source"},"System vs End-to-end Tests (",(0,s.kt)("a",{parentName:"h2",href:"https://www.geeksforgeeks.org/difference-between-system-testing-and-end-to-end-testing/"},"source"),")"),(0,s.kt)("table",null,(0,s.kt)("thead",{parentName:"table"},(0,s.kt)("tr",{parentName:"thead"},(0,s.kt)("th",{parentName:"tr",align:null},"System Testing"),(0,s.kt)("th",{parentName:"tr",align:null},"End-to-end Testing"))),(0,s.kt)("tbody",{parentName:"table"},(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"In system testing, whole software or application is tested at a time."),(0,s.kt)("td",{parentName:"tr",align:null},"In end-to-end testing, behavioral flow of the software is tested.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"System testing only tests the specific software system."),(0,s.kt)("td",{parentName:"tr",align:null},"It tests the software system and the connected systems both.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"The functionality of the software is tested."),(0,s.kt)("td",{parentName:"tr",align:null},"Flow from end-to-end is tested.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"It validates the software system as per standards and specifications."),(0,s.kt)("td",{parentName:"tr",align:null},"It validated all the interfaces of the software.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"Knowledge of interconnected systems is not required."),(0,s.kt)("td",{parentName:"tr",align:null},"Knowledge about interconnected systems is required.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"It is carried out once integration testing is performed."),(0,s.kt)("td",{parentName:"tr",align:null},"It is performed after the system testing.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"It is performed both manually and automated."),(0,s.kt)("td",{parentName:"tr",align:null},"It is generally performed manually.")),(0,s.kt)("tr",{parentName:"tbody"},(0,s.kt)("td",{parentName:"tr",align:null},"It is the super set of end-to-end testing."),(0,s.kt)("td",{parentName:"tr",align:null},"It is considered as subset of the system testing.")))),(0,s.kt)("h2",{id:"white-box-vs-black-box-testing"},"White-box vs Black-box testing"),(0,s.kt)("p",null,"Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing."),(0,s.kt)("p",null,"Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing."),(0,s.kt)("h2",{id:"the-testing-pyramid"},"The Testing Pyramid"),(0,s.kt)("p",null,"A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution."),(0,s.kt)("p",null,"70% Unit tests"),(0,s.kt)("p",null,"20% Integration tests"),(0,s.kt)("p",null,"10% End-to-end tests"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," /```\\\n / E2E \\\n /_______\\\n / \\\n /Integration\\\n /_____________\\\n / \\\n / Unit \\\n/___________________\\\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/a91c512d.1ac72c7e.js b/es/assets/js/a91c512d.1ac72c7e.js new file mode 100644 index 000000000000..1056d961f435 --- /dev/null +++ b/es/assets/js/a91c512d.1ac72c7e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4449],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var o=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 a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),p=function(e){var t=o.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 o.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),c=p(n),u=r,k=c["".concat(s,".").concat(u)]||c[u]||h[u]||a;return n?o.createElement(k,l(l({ref:t},d),{},{components:n})):o.createElement(k,l({ref:t},d))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,l=new Array(a);l[0]=u;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[c]="string"==typeof e?e:r,l[1]=i;for(var p=2;p<a;p++)l[p]=n[p];return o.createElement.apply(null,l)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},6793:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>d});var o=n(7462),r=(n(7294),n(3905)),a=n(4401);const l={},i="Ethereal Engine on Docker Desktop",s={unversionedId:"host/devops_deployment/docker_desktop",id:"host/devops_deployment/docker_desktop",title:"Ethereal Engine on Docker Desktop",description:"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.",source:"@site/docs/1_host/2_devops_deployment/1_docker_desktop.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/docker_desktop",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/1_docker_desktop.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on MicroK8s (Windows)",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows"},next:{title:"Ethereal Engine on Minikube",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/minikube"}},p={},d=[{value:"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.",id:"note-udp-networking-does-not-work-properly-on-docker-desktop-as-of-this-writing-as-docker-desktop-does-not-expose-the-ip-addressesports-of-the-node-publicly-so-mediasoup-cannot-connect-over-udp-if-you-want-to-test-audiovideo-calling-or-networked-movements-please-use-minikube",level:2},{value:"Install kubectl, Helm, and Docker Desktop",id:"install-kubectl-helm-and-docker-desktop",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Enable Kubernetes in Docker Desktop",id:"enable-kubernetes-in-docker-desktop",level:2},{value:"Edit system hostfile to point EtherealEngine addresses to 127.0.0.1",id:"edit-system-hostfile-to-point-etherealengine-addresses-to-127001",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"Run build_docker_desktop.sh",id:"run-build_docker_desktopsh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],c={toc:d},h="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(h,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"ethereal-engine-on-docker-desktop"},"Ethereal Engine on Docker Desktop"),(0,r.kt)("h2",{id:"note-udp-networking-does-not-work-properly-on-docker-desktop-as-of-this-writing-as-docker-desktop-does-not-expose-the-ip-addressesports-of-the-node-publicly-so-mediasoup-cannot-connect-over-udp-if-you-want-to-test-audiovideo-calling-or-networked-movements-please-use-minikube"},"NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube."),(0,r.kt)("h2",{id:"install-kubectl-helm-and-docker-desktop"},"Install kubectl, Helm, and Docker Desktop"),(0,r.kt)("p",null,"If ",(0,r.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl"),", ",(0,r.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm"),",\nand/or ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/linux-install/"},"Docker Desktop"),"\naren't already installed on your machine, install them. Windows and Mac Docker Desktop installation instructions\ncan be found ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/windows-install/"},"here")," and ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/desktop/install/mac-install/"},"here"),"."),(0,r.kt)("p",null,"You may also need to install ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"Docker Compose")),(0,r.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,r.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local\nservices, you'll need to get the Ethereal Engine repo on your machine. This is most easily\ndone by running ",(0,r.kt)("inlineCode",{parentName:"p"},"git clone https://github.com/etherealengine/etherealengine.git")),(0,r.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,r.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,r.kt)("p",null,"If you run ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,r.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,r.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,r.kt)("inlineCode",{parentName:"p"},"./scripts/build_minikube.sh"),"."),(0,r.kt)("h2",{id:"enable-kubernetes-in-docker-desktop"},"Enable Kubernetes in Docker Desktop"),(0,r.kt)("p",null,"Inside Docker Desktop, go to Settings. There should be a section for Kubernetes (as of this writing, located\nbetween ",(0,r.kt)("inlineCode",{parentName:"p"},"Docker Engine")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Software updates")," settings). Click on that, then check the checkbox for Enable Kuberentes,\nand then click the button Apply and restart. When Docker Desktop restarts, it should now run a minikube-like Kubernetes\ncluster on startup. The Kubernetes context for this should be named ",(0,r.kt)("inlineCode",{parentName:"p"},"docker-desktop"),"."),(0,r.kt)("h2",{id:"edit-system-hostfile-to-point-etherealengine-addresses-to-127001"},"Edit system hostfile to point EtherealEngine addresses to 127.0.0.1"),(0,r.kt)("p",null,"You'll need to edit your hostfile to point certain domains to 127.0.0.1, which is how Docker Desktop routes traffic\nto its Kubernetes cluster. On Linux, this is done by running ",(0,r.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/hosts"),"."),(0,r.kt)("p",null,"Add the following line:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"127.0.0.1 local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org\n")),(0,r.kt)("p",null,"You should also see a section that looks like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"# Added by Docker Desktop\n# To allow the same kube context to work on the host and the container:\n127.0.0.1 kubernetes.docker.internal\n# End of section\n")),(0,r.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the Kubernetes cluster,\nwhere the nginx ingress server will redirect the traffic to the appropriate pod.\nThe section it automatically added is used for giving Docker containers, including the Kubernetes cluster,\naccess to the host machine."),(0,r.kt)("p",null,"Make sure to save this file after you've edited it. On Linux, at least, you need root permissions\nto edit it."),(0,r.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,r.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,r.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,r.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,r.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,r.kt)("p",null,"Make sure that kubectl is pointed at docker-desktop by running ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),",\nwhich should say 'docker-desktop'. You can also run ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts\nthat kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,r.kt)("p",null,"Once kubectl is pointed to docker-desktop, from the top of the Ethereal Engine repo, run\n",(0,r.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones\nand ",(0,r.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,r.kt)("p",null,"You can run ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in docker-desktop. After a minute or so,\nall of these pods should be in the Running state."),(0,r.kt)("h2",{id:"run-build_docker_desktopsh"},"Run build_docker_desktop.sh"),(0,r.kt)("p",null,"When docker desktop's Kubernetes cluster is running, run the following command from the root of the Ethereal Engine repo:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/build_docker_desktop.sh\n")),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,r.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your terminal:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,r.kt)("p",null,"The script builds the full-repo Docker image using several build arguments. Vite, which builds\nthe client files, uses some information from the MariaDB database created for local K8s deployments\nto fill in some variables, and needs database credentials. The script will supply default values\nfor all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST,\nVITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your Docker Desktop K8s deployment\naccessible on ",(0,r.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different\ndomain, then you'll have to set those three environment variables to what you want them to be (and also\nchange the hostfile records you made pointing those subdomains to 127.0.0.1)"),(0,r.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for\ndifferent services, it will only run the parts needed for that service. This may take up to 15 minutes,\nthough later builds should take less time as things are cached."),(0,r.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,r.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.dockerdesktop.template.values.yaml"},"template")," for this file in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,r.kt)("p",null,"If you are using local file server as explained a couple of steps earlier then, update 'local.values.yaml' variable ",(0,r.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. It's mandatory to point to ",(0,r.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,r.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,r.kt)("p",null,"Run the following command: ",(0,r.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine"),"."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,r.kt)("p",null,"After a minute or so, running ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api\nservers, and one client server in the Running state. Setting ",(0,r.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers\n(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run\n",(0,r.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),".\nThe API pods will restart and will now not attempt to reinit the database on boot."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,r.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,r.kt)(a.ZP,{mdxType:"AcceptCertificates"}))}u.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>i});var o=n(7462),r=(n(7294),n(3905));const a={toc:[]},l="wrapper";function i(e){let{components:t,...n}=e;return(0,r.kt)(l,(0,o.Z)({},a,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,r.kt)("p",null,"Go to ",(0,r.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,r.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,r.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,r.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,r.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}i.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/b04e8f41.c4913e66.js b/es/assets/js/b04e8f41.c4913e66.js new file mode 100644 index 000000000000..c0bd0aaa9ee4 --- /dev/null +++ b/es/assets/js/b04e8f41.c4913e66.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[2142],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,h=d["".concat(c,".").concat(m)]||d[m]||u[m]||r;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l<r;l++)i[l]=n[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},1173:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var o=n(7462),a=(n(7294),n(3905));const r={},i="Studio & Locations",s={unversionedId:"creator/concepts/editor_scenes_locations",id:"creator/concepts/editor_scenes_locations",title:"Studio & Locations",description:"Scene Studio",source:"@site/docs/2_creator/1_concepts/1_editor_scenes_locations.md",sourceDirName:"2_creator/1_concepts",slug:"/creator/concepts/editor_scenes_locations",permalink:"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/1_concepts/1_editor_scenes_locations.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Concepts",permalink:"/etherealengine-docs/es/docs/creator/concepts/"},next:{title:"Studio Overview",permalink:"/etherealengine-docs/es/docs/creator/studio/"}},c={},l=[{value:"Scene Studio",id:"scene-studio",level:2},{value:"Locations & Instances",id:"locations--instances",level:2}],p={toc:l},d="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"studio--locations"},"Studio & Locations"),(0,a.kt)("h2",{id:"scene-studio"},"Scene Studio"),(0,a.kt)("p",null,"Navigating to ",(0,a.kt)("inlineCode",{parentName:"p"},"/studio")," will show you the projects page, where you can open existing projects or create a new one."),(0,a.kt)("p",null,"Opening a project will route you to ",(0,a.kt)("inlineCode",{parentName:"p"},"/studio/<projectName>")," where the project studio will load. From here, you can open a scene, which will route you again to ",(0,a.kt)("inlineCode",{parentName:"p"},"/studio/<projectName>/<sceneName>")),(0,a.kt)("p",null,"The scene consists of a list of 'nodes' which act as templates / prefabs. These are what you would normally expect in a scene studio, such as models, colliders and audio, but we also support a wide range of integrations, such as shopify, wordpress and even portals to let you traverse between worlds."),(0,a.kt)("p",null,"To save a scene with Ctrl+S or in the top left Hamburger menu."),(0,a.kt)("h2",{id:"locations--instances"},"Locations & Instances"),(0,a.kt)("p",null,"Locations can be thought of as instantiations of scene. This is how you connect your scene to a shared session."),(0,a.kt)("p",null,"Locations can be loaded via the ",(0,a.kt)("inlineCode",{parentName:"p"},"/location/<locationName>")," route, where ",(0,a.kt)("inlineCode",{parentName:"p"},"locationName")," is the name of the location. By default, the locations ",(0,a.kt)("inlineCode",{parentName:"p"},"default"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"apartment")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"sky-station")," are added."),(0,a.kt)("p",null,"An ",(0,a.kt)("strong",{parentName:"p"},"instance")," is an individual session running at a location, in which users are connected together in real time. This allows the deployment to scale events and locations to potentially millions of concurrent users without having to support them all on a single instance. "),(0,a.kt)("p",null,"There are two types of instances: ",(0,a.kt)("strong",{parentName:"p"},"world")," instances and ",(0,a.kt)("strong",{parentName:"p"},"media")," instances. World instances handle the spatial objects in the scene, such as avatars, vehicles and grabbables. Media instances handle realtime audio, video and screenshare. "),(0,a.kt)("p",null,"Media instances can be tied to a location, or exist ephemerally as a group call, called parties."),(0,a.kt)("p",null,"Instances can also be customised with the 'matchmaker' functionality to create private rooms."),(0,a.kt)("p",null,"Adding a new location is done from ",(0,a.kt)("inlineCode",{parentName:"p"},"/admin/locations")," route, and live instances can be viewed from ",(0,a.kt)("inlineCode",{parentName:"p"},"/admin/instances"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/b5eb9e9a.b0e266ee.js b/es/assets/js/b5eb9e9a.b0e266ee.js new file mode 100644 index 000000000000..cdc31d7ea338 --- /dev/null +++ b/es/assets/js/b5eb9e9a.b0e266ee.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6658],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=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 a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=r,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||a;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var c=2;c<a;c++)i[c]=n[c];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7157:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var o=n(7462),r=(n(7294),n(3905));const a={},i="Installing on Windows 10+",l={unversionedId:"host/installation/windows",id:"host/installation/windows",title:"Installing on Windows 10+",description:"1. Install python 3 and add python installation directory path to 'PATH' env variable.",source:"@site/docs/1_host/1_installation/3_windows.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/windows",permalink:"/etherealengine-docs/es/docs/host/installation/windows",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/3_windows.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing on Mac OS X",permalink:"/etherealengine-docs/es/docs/host/installation/mac_os_x"},next:{title:"Installing on Windows with WSL2",permalink:"/etherealengine-docs/es/docs/host/installation/windows_wsl"}},s={},c=[],p={toc:c},d="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"installing-on-windows-10"},"Installing on Windows 10+"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Install python 3 and add python installation directory path to 'PATH' env variable."),(0,r.kt)("li",{parentName:"ol"},"Install node js"),(0,r.kt)("li",{parentName:"ol"},"Install Visual studio community edition with build tools.",(0,r.kt)("blockquote",{parentName:"li"},(0,r.kt)("p",{parentName:"blockquote"},"Note: If mediasoup is not installed properly then modify Visual studio setup to add c++ and Node.js support."))),(0,r.kt)("li",{parentName:"ol"},"Add path of MSbuild.exe (which is present in visual studio folder) into 'path' env variable (for example:",(0,r.kt)("inlineCode",{parentName:"li"}," C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin"),")"),(0,r.kt)("li",{parentName:"ol"},"Make sure to install all windows prerequisites for mediasoup as mentioned on: ",(0,r.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/#windows"},"https://mediasoup.org/documentation/v3/mediasoup/installation/#windows")),(0,r.kt)("li",{parentName:"ol"},"Install all dependencies using ",(0,r.kt)("inlineCode",{parentName:"li"},"npm i"),"."),(0,r.kt)("li",{parentName:"ol"},"If error persists then check for typos in environment variables."),(0,r.kt)("li",{parentName:"ol"},"If you are on Windows, you can use docker-compose to start the ",(0,r.kt)("inlineCode",{parentName:"li"},"scripts/docker-compose.yml")," file, or install mariadb and copy credentials (database name, username, password) from docker-compose or ",(0,r.kt)("inlineCode",{parentName:"li"},".env.local")," -- you will need to create an empty database with the matching name.")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"./start-db.sh")," only needs to be run once. If the docker image has stopped, start it again with:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"docker container start etherealengine_db\n")),(0,r.kt)("ol",{start:8},(0,r.kt)("li",{parentName:"ol"},"Check your WSL config for any incorrect networking settings.\n",(0,r.kt)("a",{parentName:"li",href:"https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network"},"https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/b68e3f8b.bb25d3c1.js b/es/assets/js/b68e3f8b.bb25d3c1.js new file mode 100644 index 000000000000..e01d243192d3 --- /dev/null +++ b/es/assets/js/b68e3f8b.bb25d3c1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[543],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>y});var r=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 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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={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,o=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),m=o,y=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return n?r.createElement(y,a(a({ref:t},p),{},{components:n})):r.createElement(y,a({ref:t},p))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:o,a[1]=l;for(var s=2;s<i;s++)a[s]=n[s];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},450:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(7462),o=(n(7294),n(3905));const i={},a="Deployment",l={unversionedId:"host/devops_deployment/readme",id:"host/devops_deployment/readme",title:"Deployment",description:"In this section you will find out how to deploy Ethereal Engine.",source:"@site/docs/1_host/2_devops_deployment/readme.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Logging with Opensearch on Docker",permalink:"/etherealengine-docs/es/docs/host/installation/opensearch"},next:{title:"Ethereal Engine on MicroK8s (Linux)",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux"}},c={},s=[],p={toc:s},d="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"deployment"},"Deployment"),(0,o.kt)("p",null,"In this section you will find out how to deploy Ethereal Engine."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/bddbf10d.e6a24914.js b/es/assets/js/bddbf10d.e6a24914.js new file mode 100644 index 000000000000..cf810dc4f82d --- /dev/null +++ b/es/assets/js/bddbf10d.e6a24914.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[8823],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(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 i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",f={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,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(l,".").concat(d)]||u[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},2401:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={},i="Ethereal for Hosts",c={unversionedId:"host/readme",id:"host/readme",title:"Ethereal for Hosts",description:"Learn how to host your own Ethereal Engine deployment",source:"@site/docs/1_host/readme.md",sourceDirName:"1_host",slug:"/host/",permalink:"/etherealengine-docs/es/docs/host/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Overview",permalink:"/etherealengine-docs/es/docs/"},next:{title:"Installation",permalink:"/etherealengine-docs/es/docs/host/installation/"}},l={},s=[],p={toc:s},u="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-for-hosts"},"Ethereal for Hosts"),(0,o.kt)("p",null,"Learn how to host your own Ethereal Engine deployment"))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/c538f40f.4ff5f4b7.js b/es/assets/js/c538f40f.4ff5f4b7.js new file mode 100644 index 000000000000..9b5233519d04 --- /dev/null +++ b/es/assets/js/c538f40f.4ff5f4b7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3850],{3905:(e,r,t)=>{t.d(r,{Zo:()=>p,kt:()=>m});var n=t(7294);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function c(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?a(Object(t),!0).forEach((function(r){o(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function i(e,r){if(null==e)return{};var t,n,o=function(e,r){if(null==e)return{};var t,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=n.createContext({}),s=function(e){var r=n.useContext(l),t=r;return e&&(t="function"==typeof e?e(r):c(c({},r),e)),t},p=function(e){var r=s(e.components);return n.createElement(l.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(t),f=o,m=u["".concat(l,".").concat(f)]||u[f]||d[f]||a;return t?n.createElement(m,c(c({ref:r},p),{},{components:t})):n.createElement(m,c({ref:r},p))}));function m(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,c=new Array(a);c[0]=f;var i={};for(var l in r)hasOwnProperty.call(r,l)&&(i[l]=r[l]);i.originalType=e,i[u]="string"==typeof e?e:o,c[1]=i;for(var s=2;s<a;s++)c[s]=t[s];return n.createElement.apply(null,c)}return n.createElement.apply(null,t)}f.displayName="MDXCreateElement"},8580:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>s});var n=t(7462),o=(t(7294),t(3905));const a={},c="Ethereal for Creators",i={unversionedId:"creator/readme",id:"creator/readme",title:"Ethereal for Creators",description:"Learn how to create, code and customize projects with Ethereal Engine",source:"@site/docs/2_creator/readme.md",sourceDirName:"2_creator",slug:"/creator/",permalink:"/etherealengine-docs/es/docs/creator/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine Admin Panel Guide",permalink:"/etherealengine-docs/es/docs/host/Admin_Dashboard/"},next:{title:"Concepts",permalink:"/etherealengine-docs/es/docs/creator/concepts/"}},l={},s=[],p={toc:s},u="wrapper";function d(e){let{components:r,...t}=e;return(0,o.kt)(u,(0,n.Z)({},p,t,{components:r,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-for-creators"},"Ethereal for Creators"),(0,o.kt)("p",null,"Learn how to create, code and customize projects with Ethereal Engine"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/c7af7f81.279e5e03.js b/es/assets/js/c7af7f81.279e5e03.js new file mode 100644 index 000000000000..f41c2770a81e --- /dev/null +++ b/es/assets/js/c7af7f81.279e5e03.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4380],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});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 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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,l=e.originalType,s=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),u=c(n),h=o,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||l;return n?a.createElement(m,i(i({ref:t},p),{},{components:n})):a.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=n.length,i=new Array(l);i[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[u]="string"==typeof e?e:o,i[1]=r;for(var c=2;c<l;c++)i[c]=n[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6030:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=n(7462),o=(n(7294),n(3905)),l=n(4401);const i={},r="Ethereal Engine on MicroK8s (Linux)",s={unversionedId:"host/devops_deployment/microk8s_linux",id:"host/devops_deployment/microk8s_linux",title:"Ethereal Engine on MicroK8s (Linux)",description:"This guide is intended for local environment and currently tested on Ubuntu.",source:"@site/docs/1_host/2_devops_deployment/0_microk8s_linux.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/microk8s_linux",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/0_microk8s_linux.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Deployment",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/"},next:{title:"Ethereal Engine on MicroK8s (Windows)",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows"}},c={},p=[{value:"Install Python 3",id:"install-python-3",level:2},{value:"Install Make",id:"install-make",level:2},{value:"Install kubectl, Helm and Docker",id:"install-kubectl-helm-and-docker",level:2},{value:"Download and install MicroK8s",id:"download-and-install-microk8s",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Enabling MicroK8s Addons",id:"enabling-microk8s-addons",level:2},{value:"Add MicroK8s to Kubectl",id:"add-microk8s-to-kubectl",level:2},{value:"(Optional) Add MicroK8s to Lens",id:"optional-add-microk8s-to-lens",level:2},{value:"Enable MicroK8s access for local docker",id:"enable-microk8s-access-for-local-docker",level:2},{value:"Verify and troubleshoot MicroK8s",id:"verify-and-troubleshoot-microk8s",level:2},{value:"Update system hostfile to point to MicroK8s",id:"update-system-hostfile-to-point-to-microk8s",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"(Optional) Install Elastic Search and Kibana using Helm for Server Logs",id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Run build_microk8s.sh",id:"run-build_microk8ssh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],u={toc:p},d="wrapper";function h(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"ethereal-engine-on-microk8s-linux"},"Ethereal Engine on MicroK8s (Linux)"),(0,o.kt)("p",null,"This guide is intended for local environment and currently tested on Ubuntu."),(0,o.kt)("h2",{id:"install-python-3"},"Install Python 3"),(0,o.kt)("p",null,"In your WSL Ubuntu terminal, if python 3 (",(0,o.kt)("inlineCode",{parentName:"p"},"pip3 --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y python3-pip\n")),(0,o.kt)("p",null,"You can verify pip3 by using ",(0,o.kt)("inlineCode",{parentName:"p"},"pip3 --version")," command."),(0,o.kt)("h2",{id:"install-make"},"Install Make"),(0,o.kt)("p",null,"In your WSL Ubuntu terminal, if make (",(0,o.kt)("inlineCode",{parentName:"p"},"make --version"),") isn't already installed on your machine. You can do so by running following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get update -y\nsudo apt-get install -y build-essential\n")),(0,o.kt)("p",null,"You can verify make by using ",(0,o.kt)("inlineCode",{parentName:"p"},"make --version")," command."),(0,o.kt)("h2",{id:"install-kubectl-helm-and-docker"},"Install kubectl, Helm and Docker"),(0,o.kt)("p",null,"If ",(0,o.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl"),", ",(0,o.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm")," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/get-docker/"},"Docker")," aren't already installed on your machine, install them."),(0,o.kt)("p",null,"You may also need to install ",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"Docker Compose")),(0,o.kt)("h2",{id:"download-and-install-microk8s"},"Download and install MicroK8s"),(0,o.kt)("p",null,"Instructions can be found ",(0,o.kt)("a",{parentName:"p",href:"https://ubuntu.com/tutorials/install-a-local-kubernetes-with-microk8s#1-overview"},"here")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo snap install microk8s --classic --channel=1.26/stable\n")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.")),(0,o.kt)("p",null,"While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it."),(0,o.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,o.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/etherealengine/etherealengine.git etherealengine\n")),(0,o.kt)("p",null,"If ",(0,o.kt)("inlineCode",{parentName:"p"},".env.local")," file does not exist in the root of your repo folder then create it by duplicating ",(0,o.kt)("inlineCode",{parentName:"p"},".env.local.default"),"."),(0,o.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,o.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,o.kt)("p",null,"If you run ",(0,o.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,o.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,o.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,o.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,o.kt)("inlineCode",{parentName:"p"},"./scripts/build_microk8s.sh"),"."),(0,o.kt)("h2",{id:"enabling-microk8s-addons"},"Enabling MicroK8s Addons"),(0,o.kt)("p",null,"Execute following command in your terminal to enable MicroK8s addons"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3")),(0,o.kt)("h2",{id:"add-microk8s-to-kubectl"},"Add MicroK8s to Kubectl"),(0,o.kt)("p",null,"First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command in terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config delete-context microk8s\nkubectl config delete-cluster microk8s-cluster\nkubectl config delete-user microk8s-admin\n")),(0,o.kt)("p",null,"Now, we will add microk8s configuration to kubectl config. We can do this by using following commands. ",(0,o.kt)("a",{parentName:"p",href:"https://discuss.kubernetes.io/t/use-kubectl-with-microk8s/5313/6"},"Reference")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt\nkubectl config set-credentials microk8s-admin --token=\"$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')\"\nkubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin\n")),(0,o.kt)("p",null,"Afterwards you can use this newly create context by executing ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config use-context microk8s")),(0,o.kt)("p",null,"Now if you run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," command then microk8s should be current context."),(0,o.kt)("h2",{id:"optional-add-microk8s-to-lens"},"(Optional) Add MicroK8s to Lens"),(0,o.kt)("p",null," If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool ",(0,o.kt)("a",{parentName:"p",href:"https://k8slens.dev/"},"Lens"),". Else you can print the configuration using following command:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"microk8s config")),(0,o.kt)("p",null,"Option 1: If you have kubectl already installed, use ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo gedit ~/.kube/config")," as add the above output in it.",(0,o.kt)("br",{parentName:"p"}),"\n","Option 2: In Lens, goto ",(0,o.kt)("inlineCode",{parentName:"p"},"File")," > ",(0,o.kt)("inlineCode",{parentName:"p"},"Add Cluster")," and paste the output of above command to add cluster."),(0,o.kt)("h2",{id:"enable-microk8s-access-for-local-docker"},"Enable MicroK8s access for local docker"),(0,o.kt)("p",null,"For MicroK8s we will be using MicroK8s local ",(0,o.kt)("a",{parentName:"p",href:"https://microk8s.io/docs/registry-built-in"},"registry")),(0,o.kt)("p",null,"Add the following lines to ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/docker/daemon.json"),". On Linux, this is done by running ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/docker/daemon.json"),". "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{ \n "insecure-registries" : ["localhost:32000"] \n}\n')),(0,o.kt)("p",null,"Afterwards, restart docker with: ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo systemctl restart docker")),(0,o.kt)("h2",{id:"verify-and-troubleshoot-microk8s"},"Verify and troubleshoot MicroK8s"),(0,o.kt)("p",null,"Run ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo microk8s inspect")," and check if there is any warning. Its recommended to fixed the warning for MicroK8s to work properly. Following are some of the warnings and their possible fixes:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"WARNING: This machine's hostname contains capital letters and/or underscores. This is not a valid name for a Kubernetes node, causing node registration to fail. Please change the machine's hostname or refer to the documentation for more details."),(0,o.kt)("p",{parentName:"li"},"Possible Fix: ",(0,o.kt)("a",{parentName:"p",href:"https://askubuntu.com/a/87687/1558816"},"https://askubuntu.com/a/87687/1558816"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"WARNING: The memory cgroup is not enabled. The cluster may not be functioning properly. Please ensure cgroups are enabled "),(0,o.kt)("p",{parentName:"li"},"Possible Fix: ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/canonical/microk8s/issues/1691#issuecomment-1265788228"},"https://github.com/canonical/microk8s/issues/1691#issuecomment-1265788228"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"WARNING: IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo iptables -P FORWARD ACCEPT")),(0,o.kt)("p",{parentName:"li"},"The change can be made persistent with: ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo apt-get install iptables-persistent"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"MicroK8s is not running. Use microk8s inspect for a deeper inspection."),(0,o.kt)("p",{parentName:"li"},"Possible Fix: ",(0,o.kt)("a",{parentName:"p",href:"https://lightrun.com/answers/canonical-microk8s-microk8s-is-not-running-microk8sinspect-showing-no-error"},"https://lightrun.com/answers/canonical-microk8s-microk8s-is-not-running-microk8sinspect-showing-no-error")),(0,o.kt)("p",{parentName:"li"},"Here this error cloud be due to conflicting kubectl being installed. Use this command to remove kubectl ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo rm -rf /usr/local/bin/kubectl")))),(0,o.kt)("h2",{id:"update-system-hostfile-to-point-to-microk8s"},"Update system hostfile to point to MicroK8s"),(0,o.kt)("p",null,"You'll need to edit your hostfile to point certain domains to host machine IP address. On Linux, this is done by running ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/hosts"),"."),(0,o.kt)("p",null,"Add/Update the following lines:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"127.0.0.1 local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org")),(0,o.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod."),(0,o.kt)("p",null,"Make sure to save this file after you've edited it. On Linux, at least, you need root permissions to edit it."),(0,o.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,o.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,o.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,o.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,o.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,o.kt)("p",null,"Make sure that kubectl is pointed at MicroK8s by running ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),", which should say 'microk8s'. You can also run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,o.kt)("p",null,"Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones and ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("p",null,"You can run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state."),(0,o.kt)("h2",{id:"optional-install-elastic-search-and-kibana-using-helm-for-server-logs"},"(Optional) Install Elastic Search and Kibana using Helm for Server Logs"),(0,o.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,o.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,o.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,o.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,o.kt)("p",null,"Now check if the cluster members are up: ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,o.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,o.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana")),(0,o.kt)("p",null,"Check if all the pods are ready: ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,o.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,o.kt)("inlineCode",{parentName:"p"},"http://localhost:5601")," in your browser"),(0,o.kt)("p",null,"In order to connect logger with elasticsearch, update ",(0,o.kt)("inlineCode",{parentName:"p"},"local.microk8s.template.values.yaml")," env ",(0,o.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"local.microk8s.template.values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("h2",{id:"run-build_microk8ssh"},"Run build_microk8s.sh"),(0,o.kt)("p",null,"When microk8s is running, run the following command from the root of the Ethereal Engine repo:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/build_microk8s.sh\n")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,o.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your terminal:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,o.kt)("p",null,"The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on ",(0,o.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)"),(0,o.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached."),(0,o.kt)("p",null,"Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting ",(0,o.kt)("a",{parentName:"p",href:"http://localhost:32000/v2/_catalog"},"http://localhost:32000/v2/_catalog"),"."),(0,o.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,o.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.microk8s.template.values.yaml"},"template")," for this file in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,o.kt)("p",null,"If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable ",(0,o.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to ",(0,o.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,o.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,o.kt)("p",null,"Run the following command: ",(0,o.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine"),"."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("p",null,"After a minute or so, running ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting ",(0,o.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run ",(0,o.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),". The API pods will restart and will now not attempt to reinit the database on boot."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,o.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,o.kt)(l.ZP,{mdxType:"AcceptCertificates"}))}h.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>r});var a=n(7462),o=(n(7294),n(3905));const l={toc:[]},i="wrapper";function r(e){let{components:t,...n}=e;return(0,o.kt)(i,(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,o.kt)("p",null,"Go to ",(0,o.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,o.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,o.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,o.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,o.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}r.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/cc938c89.5505f774.js b/es/assets/js/cc938c89.5505f774.js new file mode 100644 index 000000000000..02fb4b722e83 --- /dev/null +++ b/es/assets/js/cc938c89.5505f774.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3709],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?s(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="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,a=e.mdxType,s=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||s;return n?r.createElement(h,i(i({ref:t},p),{},{components:n})):r.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=n.length,i=new Array(s);i[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var c=2;c<s;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},4458:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>s,metadata:()=>o,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const s={hide_table_of_contents:!0},i="Writing Good Tests",o={unversionedId:"creator/testing/test_driven_development",id:"creator/testing/test_driven_development",title:"Writing Good Tests",description:"Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:",source:"@site/docs/2_creator/6_testing/3_test_driven_development.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/test_driven_development",permalink:"/etherealengine-docs/es/docs/creator/testing/test_driven_development",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/3_test_driven_development.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{hide_table_of_contents:!0},sidebar:"tutorialSidebar",previous:{title:"Writing Reasonable & Testable Code",permalink:"/etherealengine-docs/es/docs/creator/testing/reasonable_code"},next:{title:"Debugging",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging"}},l={},c=[{value:"Test-Driven Development (source)",id:"test-driven-development-source",level:2},{value:"Antipatterns",id:"antipatterns",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"writing-good-tests"},"Writing Good Tests"),(0,a.kt)("p",null,"Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Mock"),(0,a.kt)("li",{parentName:"ol"},"Run"),(0,a.kt)("li",{parentName:"ol"},"Assert")),(0,a.kt)("p",null,"First, mock up data for the input parameters."),(0,a.kt)("p",null,"Then, run the function with the input data to produce an output."),(0,a.kt)("p",null,"Finally, assert that the output is correct."),(0,a.kt)("h2",{id:"test-driven-development-source"},"Test-Driven Development (",(0,a.kt)("a",{parentName:"h2",href:"https://en.wikipedia.org/wiki/Test-driven_development"},"source"),")"),(0,a.kt)("p",null,"Test-driven development (TDD) is a software development process relying on software requirements being converted to test cases before software is fully developed, and tracking all software development by repeatedly testing the software against all test cases. This is as opposed to software being developed first and test cases created later. "),(0,a.kt)("p",null,"This methodology is extremely useful and productive, because it means that your code will ",(0,a.kt)("em",{parentName:"p"},"always")," have test coverage. Not only that, but you can save time by ensuring that the feature is working simply by virtue of the tests passing, instead of having to run the entire software to see whether or not the feature or module in question is functioning correctly."),(0,a.kt)("p",null,"The following sequence is based on the book Test-Driven Development by Example:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Add a test"),(0,a.kt)("p",{parentName:"li"},"The adding of a new feature begins by writing a test that passes if and ",(0,a.kt)("em",{parentName:"p"},"only")," if the feature's specifications are met. The developer can discover these specifications by asking about use cases and user stories. A key benefit of test-driven development is that it makes the developer focus on requirements before writing code. This is in contrast with the usual practice, where unit tests are only written after code.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Run all tests. The new test should fail for expected reasons"),(0,a.kt)("p",{parentName:"li"},"This shows that new code is actually needed for the desired feature. It validates that the test harness is working correctly. It rules out the possibility that the new test is flawed and will always pass.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Write the simplest code that passes the new test"),(0,a.kt)("p",{parentName:"li"},"Inelegant or hard code is acceptable, as long as it passes the test. The code will be honed anyway in Step 5. No code should be added beyond the tested functionality.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"All tests should now pass"),(0,a.kt)("p",{parentName:"li"},"If any fail, the new code must be revised until they pass. This ensures the new code meets the test requirements and does not break existing features.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Refactor as needed, using tests after each refactor to ensure that functionality is preserved"),(0,a.kt)("p",{parentName:"li"},"Code is refactored for readability and maintainability. In particular, hard-coded test data should be removed. Running the test suite after each refactor helps ensure that no existing functionality is broken."),(0,a.kt)("p",{parentName:"li"},"Examples of refactoring:"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"moving code to where it most logically belongs"),(0,a.kt)("li",{parentName:"ul"},"removing duplicate code"),(0,a.kt)("li",{parentName:"ul"},"making names self-documenting"),(0,a.kt)("li",{parentName:"ul"},"splitting methods into smaller pieces"),(0,a.kt)("li",{parentName:"ul"},"re-arranging inheritance hierarchies")))),(0,a.kt)("p",null,"The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply undo or revert rather than debug excessively. When using external libraries, it is important not to write tests that are so small as to effectively test merely the library itself, unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development."),(0,a.kt)("h3",{id:"antipatterns"},"Antipatterns"),(0,a.kt)("p",null,'Practices to avoid, or "anti-patterns"'),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Having test cases depend on system state manipulated from previously executed test cases (i.e., you should always start a unit test from a known and pre-configured state)."),(0,a.kt)("li",{parentName:"ul"},"Dependencies between test cases. A test suite where test cases are dependent upon each other is brittle and complex. Execution order should not be presumed. Basic refactoring of the initial test cases or structure of the UUT causes a spiral of increasingly pervasive impacts in associated tests."),(0,a.kt)("li",{parentName:"ul"},"Interdependent tests. Interdependent tests can cause cascading false negatives. A failure in an early test case breaks a later test case even if no actual fault exists in the UUT, increasing defect analysis and debug efforts."),(0,a.kt)("li",{parentName:"ul"},"Testing precise execution behavior timing or performance."),(0,a.kt)("li",{parentName:"ul"},'Building "all-knowing oracles". An oracle that inspects more than necessary is more expensive and brittle over time. This very common error is dangerous because it causes a subtle but pervasive time sink across the complex project.'),(0,a.kt)("li",{parentName:"ul"},"Testing implementation details."),(0,a.kt)("li",{parentName:"ul"},"Slow running tests.")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/cf339e2e.43e40fa8.js b/es/assets/js/cf339e2e.43e40fa8.js new file mode 100644 index 000000000000..d20147f4c4c0 --- /dev/null +++ b/es/assets/js/cf339e2e.43e40fa8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4438],{5745:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-pages","id":"default"}')}}]); \ No newline at end of file diff --git a/es/assets/js/d05402c5.90cf9c7a.js b/es/assets/js/d05402c5.90cf9c7a.js new file mode 100644 index 000000000000..a5dc808411ce --- /dev/null +++ b/es/assets/js/d05402c5.90cf9c7a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[6970],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=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 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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}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},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(n),h=o,f=u["".concat(s,".").concat(h)]||u[h]||d[h]||i;return n?r.createElement(f,a(a({ref:t},p),{},{components:n})):r.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:o,a[1]=c;for(var l=2;l<i;l++)a[l]=n[l];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},6064:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const i={},a="Event Sourcing",c={unversionedId:"creator/development/actions_event_sourcing",id:"creator/development/actions_event_sourcing",title:"Event Sourcing",description:"Actions",source:"@site/docs/2_creator/4_development/4_actions_event_sourcing.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/actions_event_sourcing",permalink:"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/4_actions_event_sourcing.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Networking",permalink:"/etherealengine-docs/es/docs/creator/development/networking"},next:{title:"Introduction",permalink:"/etherealengine-docs/es/docs/creator/development/behave_graph"}},s={},l=[{value:"Actions",id:"actions",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...i}=e;return(0,o.kt)(u,(0,r.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"event-sourcing"},"Event Sourcing"),(0,o.kt)("h2",{id:"actions"},"Actions"),(0,o.kt)("p",null,"Actions are a way to control state changes in your application. Once defined, they can be dispatched, which will then populate the outgoing queue to be processed on the next frame."),(0,o.kt)("p",null,"All actions are dispatched to a topic, by default this is the ",(0,o.kt)("strong",{parentName:"p"},"default")," topic. Topics are used to specify that actions are to be routed to specific networks."),(0,o.kt)("p",null,"When an action is dispatched, it is added to the incoming action queue. If it's topic is networked, it is also added to the outgoing queue for it's topic."),(0,o.kt)("p",null,"At the end of the animation frame, any actions in a network topic's outgoing queue are sent to that topic's network."),(0,o.kt)("p",null,"If the peer is the host of a networked action's topic, the action is sent to all other peers, otherwise it is just sent to the host. This can be opted out of by specifying the $to property on an action, which informs the host to forward the action only to that user's."),(0,o.kt)("p",null,"At the start of the next animation frame, action queues are populated with incoming actions. These actions are then processed in the order they were received, by systems in the order the systems are registered."),(0,o.kt)("p",null,(0,o.kt)("img",{src:n(8608).Z,width:"1229",height:"389"})))}d.isMDXComponent=!0},8608:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/action-flow-60986ff90c8d31b59daae05f970d318e.png"}}]); \ No newline at end of file diff --git a/es/assets/js/d43455fa.4846077f.js b/es/assets/js/d43455fa.4846077f.js new file mode 100644 index 000000000000..5e6028382f0c --- /dev/null +++ b/es/assets/js/d43455fa.4846077f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1205],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var o=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 r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=o.createContext({}),l=function(e){var t=o.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return o.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=l(n),u=a,h=m["".concat(p,".").concat(u)]||m[u]||d[u]||r;return n?o.createElement(h,i(i({ref:t},c),{},{components:n})):o.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=u;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var l=2;l<r;l++)i[l]=n[l];return o.createElement.apply(null,i)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},9347:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>l});var o=n(7462),a=(n(7294),n(3905));const r={},i="Entities, Components and Systems",s={unversionedId:"creator/development/ecs",id:"creator/development/ecs",title:"Entities, Components and Systems",description:"What is an ECS?",source:"@site/docs/2_creator/4_development/2_ecs.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/ecs",permalink:"/etherealengine-docs/es/docs/creator/development/ecs",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/2_ecs.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"State Management",permalink:"/etherealengine-docs/es/docs/creator/development/state_management"},next:{title:"Networking",permalink:"/etherealengine-docs/es/docs/creator/development/networking"}},p={},l=[{value:"What is an ECS?",id:"what-is-an-ecs",level:2},{value:"Component Definitions",id:"component-definitions",level:2},{value:"Structure of Arrays Component Data",id:"structure-of-arrays-component-data",level:3},{value:"Reactive Component Data",id:"reactive-component-data",level:3},{value:"onInit",id:"oninit",level:3},{value:"onSet",id:"onset",level:3},{value:"onRemove",id:"onremove",level:3},{value:"toJSON",id:"tojson",level:3},{value:"jsonID",id:"jsonid",level:2},{value:"reactor",id:"reactor",level:3},{value:"Update Loop",id:"update-loop",level:2},{value:"Queries",id:"queries",level:2},{value:"Examples",id:"examples",level:2},{value:"Timer",id:"timer",level:3},{value:"References",id:"references",level:2}],c={toc:l},m="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"entities-components-and-systems"},"Entities, Components and Systems"),(0,a.kt)("h2",{id:"what-is-an-ecs"},"What is an ECS?"),(0,a.kt)("p",null,'ECS refers to the "Entity Component System" architecture paradigm. In this pattern, data is organised into abstract objects called ',(0,a.kt)("strong",{parentName:"p"},"components")," that allows for composition instead of inheritance. An ",(0,a.kt)("strong",{parentName:"p"},"entity")," is simply collection of components identified by a number. ",(0,a.kt)("strong",{parentName:"p"},"Systems")," are functions that operate on these entities and components."),(0,a.kt)("h2",{id:"component-definitions"},"Component Definitions"),(0,a.kt)("p",null,"Components support two types of data: Structure of Arrays and Array of Structures."),(0,a.kt)("h3",{id:"structure-of-arrays-component-data"},"Structure of Arrays Component Data"),(0,a.kt)("p",null,"Structure of Arrays is a data layout that stores data in a way that is more cache friendly. It is a good choice for data that is accessed often and in a predictable way, such as transform data."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const TransformComponent = defineComponent({\n name: 'TransformComponent',\n schema: {\n position: Types.f64,\n rotation: Types.f64,\n scale: Types.f64\n }\n})\n")),(0,a.kt)("h3",{id:"reactive-component-data"},"Reactive Component Data"),(0,a.kt)("p",null,"Array of Structures is an implementation unique to Ethereal Engine, using React and Hookstate under the hood, it allows for reactive data binding. This means that when a property is changed, all effects depending on it will be triggered. It is a good choice for data that is accessed infrequently and in an unpredictable way, especially when react style logic is associated with it."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const DebugArrowComponent = defineComponent({\n name: 'DebugArrowComponent',\n\n onInit: (entity) => {\n return {\n color: 0xffffff,\n direction: new Vector3(),\n position: new Vector3()\n }\n },\n\n onSet: (entity, component, json) => {\n if (!json) return\n\n if (json.color) component.color.set(json.color)\n if (json.direction) component.direction.set(json.direction)\n if (json.position) component.position.set(json.position)\n }\n})\n")),(0,a.kt)("h3",{id:"oninit"},"onInit"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"(entity: Entity) => ComponentType<C>")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"onInit")," is a function that is called when ",(0,a.kt)("strong",{parentName:"p"},"setComponent")," is called on an entity that does not have the component in question. It is passed the entity number and should return an object with the initial values for the component."),(0,a.kt)("h3",{id:"onset"},"onSet"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"entity: Entity, component: ComponentType<C>, json: SerializedComponentType<C>) => void")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"onSet")," is a function that is called each time ",(0,a.kt)("strong",{parentName:"p"},"setComponent")," is called. It is passed the entity number, the component object and json object. This is how reactive data can be updated in batch, allowing for tighter data flow, such as deserializing scene data."),(0,a.kt)("h3",{id:"onremove"},"onRemove"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"(entity: Entity, component: ComponentType<C>) => void")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"onRemove")," is a function that is called when ",(0,a.kt)("strong",{parentName:"p"},"removeComponent")," is called on an entity that has the component in question. It is passed the entity number and the component object. This is where you would clean up any resources associated with the component."),(0,a.kt)("h3",{id:"tojson"},"toJSON"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"(entity: Entity, component: ComponentType<C>) => SerializedComponentType<C>")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"toJSON")," is a function that is called when ",(0,a.kt)("strong",{parentName:"p"},"serializeComponent")," is called on an entity that has the component in question. It is passed the entity number and the component object. This is where serialized data can be generated, such as for saving a scene."),(0,a.kt)("h2",{id:"jsonid"},"jsonID"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"string")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"jsonID")," is a string that is used to identify the component in json. It is used when deserializing and serializing scenes."),(0,a.kt)("h3",{id:"reactor"},"reactor"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"function(props: { root: EntityRoot }) => void")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"reactor")," specifies a function that exists for the duration of this component instance. This is where you would add any effects that depend on the component."),(0,a.kt)("h2",{id:"update-loop"},"Update Loop"),(0,a.kt)("p",null,"The engine uses a very similar model to Unity's update loop (found here ",(0,a.kt)("a",{parentName:"p",href:"https://docs.unity3d.com/Manual/ExecutionOrder.html"},"https://docs.unity3d.com/Manual/ExecutionOrder.html"),"). It has a frame update, called once per frame, of which inside is a fixed update, which operates on an accumulator system. This system ensures a stable number of updates per second independent of the framerate. This means it may have 0 to many updates in a given frame. "),(0,a.kt)("p",null,"Ethereal Engine implements this with ",(0,a.kt)("strong",{parentName:"p"},"pipelines"),", which are collections of systems to execute in order."),(0,a.kt)("h2",{id:"queries"},"Queries"),(0,a.kt)("p",null,"Queries are used to select entities that have a set of components. They are used to define the entities that a system will operate on. Queries are defined using the ",(0,a.kt)("strong",{parentName:"p"},"defineQuery")," function."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const query = defineQuery([TransformComponent, GroupComponent])\n\nconst entities = query() // returns an array of entity numbers\n")),(0,a.kt)("p",null,"Queries also have enter and exit derivatives, which are used to define when a combination of components is added or removed from an entity. These are defined using the ",(0,a.kt)("strong",{parentName:"p"},"defineEnterQuery")," and ",(0,a.kt)("strong",{parentName:"p"},"defineExitQuery")," functions."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const query = defineQuery([TransformComponent, GroupComponent])\n\nconst allEntities = query()\nconst enterEntities = query.enter()\nconst exitEntities = query.exit()\n")),(0,a.kt)("h2",{id:"examples"},"Examples"),(0,a.kt)("h3",{id:"timer"},"Timer"),(0,a.kt)("p",null,"The follow code snippets, we define a component and a system. The component will hold a property to store the current elapsed time rounded down."),(0,a.kt)("p",null,"In the ",(0,a.kt)("strong",{parentName:"p"},"initializer")," of the system, it creates a new entity and adds the component to it. In the ",(0,a.kt)("strong",{parentName:"p"},"execute")," function of the system, we set the property ",(0,a.kt)("inlineCode",{parentName:"p"},"time")," on the component of the entity."),(0,a.kt)("p",null,"This example uses 'Structure of Arrays' (SoA) data structures with bitECS syntax."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const TimerComponent = defineComponent({\n name: 'TimerComponent',\n schema: {\n time: Types.f32\n }\n})\n\nconst timerQuery = defineQuery([TimerComponent])\n\nconst execute = () => {\n const { deltaSeconds } = getState(EngineState)\n\n for (const entity of timerQuery()) {\n TimerComponent.time[entity] += delta\n }\n}\n\nexport const TimerSystem = defineSystem({\n uuid: 'TimerSystem',\n execute\n})\n\n")),(0,a.kt)("p",null,"This example uses 'Array of Structures' syntax, with reactive data binding."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"const TimerComponent = defineComponent({\n name: 'TimerComponent',\n onInit: (entity) => {\n return {\n time: 0\n }\n },\n onSet: (entity, component, json) => {\n if (typeof json?.time === 'number') component.time.set(json.time)\n },\n toJSON: (entity, component) => {\n return {\n time: component.time.value\n }\n }\n})\n\nconst timerQuery = defineQuery([TimerComponent])\n\nconst execute = () => {\n const { elapsedSeconds } = getState(EngineState)\n\n for (const entity of timerQuery()) {\n const timerComponent = getMutableComponent(entity, TimerComponent)\n timerComponent.time.set(Math.floor(elapsedSeconds))\n }\n}\n\nexport const TimerSystem = defineSystem({\n uuid: 'TimerSystem',\n execute\n})\n\n")),(0,a.kt)("h2",{id:"references"},"References"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=2rW7ALyHaas"},"Entity Component System Overview in 7 Minutes")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=qaY_CKvFLYM"},"Entity Component System in TypeScript with Phaser 3 and bitECS)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=W3aieHjyNvw"},"Overwatch GDC ECS & Netcode")," (note, ethereal engine does not use this style of networking)")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/d50cf8bd.2f6b2995.js b/es/assets/js/d50cf8bd.2f6b2995.js new file mode 100644 index 000000000000..083bee3f7344 --- /dev/null +++ b/es/assets/js/d50cf8bd.2f6b2995.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[1364],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var r=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 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 s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),p=c(n),g=o,h=p["".concat(l,".").concat(g)]||p[g]||u[g]||a;return n?r.createElement(h,s(s({ref:t},d),{},{components:n})):r.createElement(h,s({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=g;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:o,s[1]=i;for(var c=2;c<a;c++)s[c]=n[c];return r.createElement.apply(null,s)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},9466:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={},s="Debugging Deployed Instanceservers (and other Kubernetes pods)",i={unversionedId:"creator/testing/debugging_deployed_instanceservers",id:"creator/testing/debugging_deployed_instanceservers",title:"Debugging Deployed Instanceservers (and other Kubernetes pods)",description:"Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear",source:"@site/docs/2_creator/6_testing/6_debugging_deployed_instanceservers.md",sourceDirName:"2_creator/6_testing",slug:"/creator/testing/debugging_deployed_instanceservers",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/6_testing/6_debugging_deployed_instanceservers.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Debugging Engine in WSL on Phone/Headset",permalink:"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl"},next:{title:"readme",permalink:"/etherealengine-docs/es/docs/creator/avatars/"}},l={},c=[],d={toc:c},p="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(p,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"debugging-deployed-instanceservers-and-other-kubernetes-pods"},"Debugging Deployed Instanceservers (and other Kubernetes pods)"),(0,o.kt)("p",null,"Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear\nbefore one has a chance to view them, as the pods that they were on are deleted, along with their logs."),(0,o.kt)("p",null,"One way to catch these errors is to tail the logs of existing pods from a local machine and then trigger the error.\nThe tail of the logs will persist in your terminal even after the pod has been deleted."),(0,o.kt)("p",null,"You should already have kubectl set up and pointing to your cluster, but if not, do so.\n(see ",(0,o.kt)("a",{parentName:"p",href:"../2_devops_deployment/5_managing_remote_kubernetes.md"},"here")," for links to do that)\nMake sure you don't have a browser tab with the offending location(s) open already, as you want to be tailing\nthe logs before the instance starts."),(0,o.kt)("p",null,"Next, run ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get gs"),". If the cluster is fully installed, this will get all of the running instanceserver\npods (",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," will get all pods, if you need to find the names of API pods, etc.)\nSelect the Name of a pod and copy it (in Linux, highlight it and press CTRL+SHIFT+C), then run\n",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs <pod_name> -c <RELEASE_NAME>-instanceserver -f"),",\ne.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs prod-instanceserver-vhwh2-9vqrv -c prod-instanceserver -f"),". It should output something like this for\nand instanceserver pod:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'> @etherealengine/instanceserver@1.3.0 start\n> cross-env APP_ENV=production ts-node --swc src/index.ts\n\n\ud83d\udc7e bitECS - resizing all data stores from 100000 to 5000\n Powered by three.quarks. https://quarks.art/\n[hyperflux:Action] Added topic default\n[hyperflux:State] registerState SceneState\n[hyperflux:Action] Added Receptor EngineEventReceptor\n[hyperflux:State] registerState EngineState\n[hyperflux:State] registerState ServerState\nTue, 11 Jul 2023 00:38:50 GMT koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md at ../../node_modules/@feathersjs/koa/lib/index.js:52:27\n[00:38:50.631] INFO: Starting app.\n component: "server-core:sequelize"\n[hyperflux:State] registerState NetworkState\n[00:38:50.645] INFO: Starting app.\n component: "server-core:mysql"\n[00:38:50.900] INFO: registered kickCreatedListener\n component: "instanceserver:channels"\n[00:38:50.901] INFO: Starting instanceserver with NO HTTPS on 3031, if you meant to use HTTPS try \'sudo bash generate-certs\'\n component: "instanceserver"\n[00:38:51.036] INFO: Feathers-sync started.\n component: "server-core"\n[00:38:51.634] INFO: Server Ready\n component: "server-core:sequelize"\n\n')),(0,o.kt)("p",null,"Since the instanceserver pod that is picked to handle a given world or media instance is random, you'll want to\nopen a few more tabs in your terminal and repeat the above ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs")," command, substituting a different\ninstanceserver pod name in each tab, so that you're tailing all of the current pods. Then go to the location that is\ndisplaying problematic behavior, or otherwise trigger the action that is causing problems, and you should see the error\nin one of the terminals. If it's a fatal error, the logging will end with the pod, but the logs will stay in that terminal."),(0,o.kt)("p",null,"Note that if you want to log further errors, you may need to get the names of the new pods that are spun up to replace\nthe ones that crashed by running ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get gs")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," again, and then using the new pods' names in\n",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl logs")," commands."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/d519f5a1.105895aa.js b/es/assets/js/d519f5a1.105895aa.js new file mode 100644 index 000000000000..a66915579708 --- /dev/null +++ b/es/assets/js/d519f5a1.105895aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5046],{3905:(e,t,n)=>{n.d(t,{Zo:()=>h,kt:()=>g});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 l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}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},h=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={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,o=e.mdxType,i=e.originalType,s=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),u=p(n),c=o,g=u["".concat(s,".").concat(c)]||u[c]||d[c]||i;return n?a.createElement(g,l(l({ref:t},h),{},{components:n})):a.createElement(g,l({ref:t},h))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=c;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[u]="string"==typeof e?e:o,l[1]=r;for(var p=2;p<i;p++)l[p]=n[p];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},806:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={},l="Introduction",r={unversionedId:"creator/development/behave_graph",id:"creator/development/behave_graph",title:"Introduction",description:"* Overview",source:"@site/docs/2_creator/4_development/5_behave_graph.md",sourceDirName:"2_creator/4_development",slug:"/creator/development/behave_graph",permalink:"/etherealengine-docs/es/docs/creator/development/behave_graph",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/2_creator/4_development/5_behave_graph.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Event Sourcing",permalink:"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing"},next:{title:"Tutorials",permalink:"/etherealengine-docs/es/docs/creator/tutorials/"}},s={},p=[{value:"1. Introduction",id:"1-introduction",level:2},{value:"1.1 Overview",id:"11-overview",level:3},{value:"1.2 Audience",id:"12-audience",level:3},{value:"2. Getting Started",id:"2-getting-started",level:2},{value:"2.1 Installation - at the moment the behavior graph implementation is available on the behave-graph-integration branch in the Ethereal Engine Repository",id:"21-installation---at-the-moment-the-behavior-graph-implementation-is-available-on-the-behave-graph-integration-branch-in-the-ethereal-engine-repository",level:3},{value:"2.2 Configuration",id:"22-configuration",level:3},{value:"2.3 Creating your First graph",id:"23-creating-your-first-graph",level:3},{value:"2.3.1 buttons in the graph panel",id:"231-buttons-in-the-graph-panel",level:3},{value:"2.3.2 Saving Graph",id:"232-saving-graph",level:3},{value:"2.3.3 Playing a graph",id:"233-playing-a-graph",level:3},{value:"Ok finally with all this context, lets add a node",id:"ok-finally-with-all-this-context-lets-add-a-node",level:4},{value:"3.2 Key Concepts",id:"32-key-concepts",level:3},{value:"3.3 Engine Nodes",id:"33-engine-nodes",level:3},{value:"3.3.1 Entity",id:"331-entity",level:3},{value:"3.3.2 Component",id:"332-component",level:3},{value:"3.3.3 Engine",id:"333-engine",level:3},{value:"3.3.4 Events",id:"334-events",level:3},{value:"4. Usage",id:"4-usage",level:2},{value:"5.Configuration and Customization",id:"5configuration-and-customization",level:2},{value:"5.1 Making new nodes",id:"51-making-new-nodes",level:3}],h={toc:p},u="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,a.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"introduction"},"Introduction"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Overview"),(0,o.kt)("li",{parentName:"ul"},"Audience")),(0,o.kt)("p",null,"Getting Started"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Installation"),(0,o.kt)("li",{parentName:"ul"},"Configuration")),(0,o.kt)("p",null,"Code Overview:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"High-Level Architecture"),(0,o.kt)("li",{parentName:"ul"},"Key Concepts"),(0,o.kt)("li",{parentName:"ul"},"Engine Nodes")),(0,o.kt)("p",null,"Usage"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Examples")),(0,o.kt)("p",null,"Configuration and Customization"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Making new nodes")),(0,o.kt)("h2",{id:"1-introduction"},"1. Introduction"),(0,o.kt)("h3",{id:"11-overview"},"1.1 Overview"),(0,o.kt)("p",null,"Behavior graphs are expressive, deterministic, and extensible state machines that can encode arbitrarily complex behavior."),(0,o.kt)("p",null,"Behavior graphs are a popular choice for implementing visual scripting languages. Prominent game engines like Unreal Engine and Unity have adopted behavior graphs as an essential component of their visual scripting systems. For example, Unreal Engine's Blueprints, Unity's Visual Scripting, and NVIDIA Omniverse's OmniGraph rely on behavior graphs to enable game designers and developers to create complex behaviors without writing code directly."),(0,o.kt)("p",null,"Within the Ethereal Engine, the Behavior Graphs feature plays a pivotal role by providing a no-code interface to the engine and by interacting with the engine while modeling, organizing, controlling and assigning complex behaviors on entities, with ease."),(0,o.kt)("h3",{id:"12-audience"},"1.2 Audience"),(0,o.kt)("p",null,"Behavior Graphs in the Ethereal engine target developers, designers, artists, and non-technical users. This visual scripting feature enables easy implementation of complex logic and actions for entities without the need for writing scripts. It fosters collaboration and empowers diverse individuals to create immersive experiences and interactive content within the engine."),(0,o.kt)("h2",{id:"2-getting-started"},"2. Getting Started"),(0,o.kt)("h3",{id:"21-installation---at-the-moment-the-behavior-graph-implementation-is-available-on-the-behave-graph-integration-branch-in-the-ethereal-engine-repository"},"2.1 Installation - at the moment the behavior graph implementation is available on the behave-graph-integration branch in the Ethereal Engine Repository"),(0,o.kt)("p",null,"Clone the branch and follow general Ethereal engine installation steps\n",(0,o.kt)("a",{parentName:"p",href:"/docs/host/installation/"},"general instructions")),(0,o.kt)("p",null,"The Behavior Graphs must be defined in the studio and thus require a user to have admin privileges"),(0,o.kt)("h3",{id:"22-configuration"},"2.2 Configuration"),(0,o.kt)("p",null,"The Behave graph is implemented as a component in the engine following the ECS(Entity component system) architecture in the engine."),(0,o.kt)("p",null,"Users can add and remove a behave graph component from an entity "),(0,o.kt)("p",null,"Step 1: find the behave graph component under the scripting section in the component shelf in the right side of the screen\nStep 2:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"double click on the component tor drag and drop into scene to add a new entity with the behave graph component into the screen"),(0,o.kt)("li",{parentName:"ol"},"Drag and drop into the hierarchy panel on another entity to add to scene as child of the selected entity"),(0,o.kt)("li",{parentName:"ol"},"Drag and drop into properties panel of selected entity to add component to entity")),(0,o.kt)("p",null,"The behave graph properties panel has two properties:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Run graph: runs the graph in headless mode as part of the engine"),(0,o.kt)("li",{parentName:"ul"},"Disable graph: disable graph from playing")),(0,o.kt)("h3",{id:"23-creating-your-first-graph"},"2.3 Creating your First graph"),(0,o.kt)("p",null,"Before we dive into creating the graph let's take a look at the graph panel"),(0,o.kt)("p",null,"The graph panel consists of the the panel itself, panel buttons, nodes and connections"),(0,o.kt)("p",null,"The default behave graph consists of an "),(0,o.kt)("p",null,"On start event node"),(0,o.kt)("p",null,"On tick event node"),(0,o.kt)("p",null,"Logger node"),(0,o.kt)("p",null,"To navigate across the panel, drag across the surface of the panel"),(0,o.kt)("h3",{id:"231-buttons-in-the-graph-panel"},"2.3.1 buttons in the graph panel"),(0,o.kt)("p",null,"The buttons panel is location in the bottom left side of the screen"),(0,o.kt)("p",null,"The buttons are as follows"),(0,o.kt)("p",null,"Zoom in: zoom into the graph viewport"),(0,o.kt)("p",null,"Zoom out: zoom out of the graph viewport"),(0,o.kt)("p",null,"Fit view: tries to fit all nodes into the screen at the same time, if not possible it centers the view at the center of all nodes"),(0,o.kt)("p",null,"Lock graph: Toggles ability to graph edit"),(0,o.kt)("p",null,"Help: Opens an instruction modal for making graphs"),(0,o.kt)("p",null,"Load Graph: Opens a modal, user can paste graph json in the input field to load the corresponding graph"),(0,o.kt)("p",null,"Save Graph: Opens a model, user can copy the graph json from the text box and save as needed"),(0,o.kt)("p",null,"Play Graph: runs headful version of the graph connected to the graph editor"),(0,o.kt)("h3",{id:"232-saving-graph"},"2.3.2 Saving Graph"),(0,o.kt)("p",null,"The graph has its own json which is also part of the scene json, therefore the user needs to save the graph in as its own json which then must be saved as a part of the scene"),(0,o.kt)("p",null,"The graph json is autosaved every 5 seconds the graph panel i open and whenever the graph panel is closed (the component unmounts)"),(0,o.kt)("p",null,"The graph and overall changes to the scene must be saved using the save scene option from the main menu"),(0,o.kt)("h3",{id:"233-playing-a-graph"},"2.3.3 Playing a graph"),(0,o.kt)("p",null,"A graph can be played in two modes, headful and headless,"),(0,o.kt)("p",null,"headful mode play - headful mode, activated by pressing the play button in the graph buttons, graph stops executing when the panel is closed or component unmounts, meant for quick testing, setting scene variables and rapid development"),(0,o.kt)("p",null,"Headless mode play - headless mode, play activated from properties panel, execution does not stop unless play is toggled off again from the properties panel"),(0,o.kt)("p",null,"To play all graphs in the scene the user can use the play scene button from the top toolbar"),(0,o.kt)("p",null,"NOTE: headful and headless plays must be managed separately"),(0,o.kt)("h4",{id:"ok-finally-with-all-this-context-lets-add-a-node"},"Ok finally with all this context, lets add a node"),(0,o.kt)("p",null,"To add a node, right click anywhere on the graph panel"),(0,o.kt)("p",null,"This will open up the node picker select window,"),(0,o.kt)("p",null,"Type in the search input to filter nodes by prefix\nClick on the node to add to the panel"),(0,o.kt)("p",null,"Lets add a logger node and connect it to the on tick event"),(0,o.kt)("p",null,"To connect the flow of the nodes , drag from one flow socket to another\nThere can be only one flow output from one flow output socket"),(0,o.kt)("p",null,"But there can be multiple inputs to a flow input socket"),(0,o.kt)("p",null,"To play the graph click on the play graph button"),(0,o.kt)("p",null,"Well done, outputs to the log can be seen in the dev tools console"),(0,o.kt)("p",null,"TODO: add pictures"),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"Code Overview:")),(0,o.kt)("p",null,"Node Types"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Events You can implement arbitrary events that start execution: Start, Tick"),(0,o.kt)("li",{parentName:"ul"},"Actions You can implement actions that trigger animations, scene scene variations, or update internal state: Log, Play Gltf animation, Play Audio, Play Video, etc"),(0,o.kt)("li",{parentName:"ul"},"Logic You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes."),(0,o.kt)("li",{parentName:"ul"},"Queries You can query the state from the system."),(0,o.kt)("li",{parentName:"ul"},"Flow Control Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop"),(0,o.kt)("li",{parentName:"ul"},"Variables You can create, set and get variable values."),(0,o.kt)("li",{parentName:"ul"},"Custom Events You can create, listen to and trigger custom events.")),(0,o.kt)("h3",{id:"32-key-concepts"},"3.2 Key Concepts"),(0,o.kt)("p",null,"Nodes -\nConnections -\nFlow -"),(0,o.kt)("p",null,"Events"),(0,o.kt)("p",null,"Set and Get Scene Properties"),(0,o.kt)("p",null,"Registering nodes"),(0,o.kt)("p",null,"Value Types"),(0,o.kt)("p",null,"Value type Converters"),(0,o.kt)("h3",{id:"33-engine-nodes"},"3.3 Engine Nodes"),(0,o.kt)("h3",{id:"331-entity"},"3.3.1 Entity"),(0,o.kt)("p",null,"Teleport Entity\nAdd Entity\nDelete Entity\nGet Entity from Scene\nGet Camera Entity"),(0,o.kt)("h3",{id:"332-component"},"3.3.2 Component"),(0,o.kt)("p",null,"Add Component"),(0,o.kt)("p",null,"Delete Component"),(0,o.kt)("p",null,"Get component from registry\nGet component from entity"),(0,o.kt)("h3",{id:"333-engine"},"3.3.3 Engine"),(0,o.kt)("p",null,"Play Video"),(0,o.kt)("p",null,"Play Audio"),(0,o.kt)("p",null,"Play Gltf Animations"),(0,o.kt)("p",null,"Get Avatar animations"),(0,o.kt)("p",null,"Fade Camera"),(0,o.kt)("p",null,"Switch Scene"),(0,o.kt)("h3",{id:"334-events"},"3.3.4 Events"),(0,o.kt)("p",null,"Either in pairs of trigger and listener , or just listener\nOn Button State"),(0,o.kt)("p",null,"triggerLoadAsset -> onLoadAsset"),(0,o.kt)("h2",{id:"4-usage"},"4. Usage"),(0,o.kt)("p",null,"Add some example screenshots and explain"),(0,o.kt)("h2",{id:"5configuration-and-customization"},"5.Configuration and Customization"),(0,o.kt)("h3",{id:"51-making-new-nodes"},"5.1 Making new nodes"),(0,o.kt)("p",null,"Describe the creation of nodes"),(0,o.kt)("p",null,"Making flow nodes\nMaking Event node\nMaking Value types"),(0,o.kt)("p",null,"Making Function node"),(0,o.kt)("p",null,"Extending Dependencies"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/d7cf77e2.d0f4d092.js b/es/assets/js/d7cf77e2.d0f4d092.js new file mode 100644 index 000000000000..5ae4e8ec05b0 --- /dev/null +++ b/es/assets/js/d7cf77e2.d0f4d092.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[314],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(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<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=a.createContext({}),d=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=d(e.components);return a.createElement(l.Provider,{value:n},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=d(t),h=r,m=u["".concat(l,".").concat(h)]||u[h]||c[h]||o;return t?a.createElement(m,i(i({ref:n},p),{},{components:t})):a.createElement(m,i({ref:n},p))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,i=new Array(o);i[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var d=2;d<o;d++)i[d]=t[d];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}h.displayName="MDXCreateElement"},7046:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=t(7462),r=(t(7294),t(3905));const o={},i="Advanced Setup",s={unversionedId:"host/installation/advanced_setup",id:"host/installation/advanced_setup",title:"Advanced Setup",description:"If you want to setup Ethereal Engine docker instances, client, server, and/or",source:"@site/docs/1_host/1_installation/4_advanced_setup.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/advanced_setup",permalink:"/etherealengine-docs/es/docs/host/installation/advanced_setup",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/4_advanced_setup.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installing on Windows with WSL2",permalink:"/etherealengine-docs/es/docs/host/installation/windows_wsl"},next:{title:"Running on Static IP under WSL2",permalink:"/etherealengine-docs/es/docs/host/installation/running_on_static_IP"}},l={},d=[{value:"1. Install your dependencies",id:"1--install-your-dependencies",level:3},{value:"2. Make sure you have a mysql database installed and running -- our recommendation is Mariadb.",id:"2-make-sure-you-have-a-mysql-database-installed-and-running----our-recommendation-is-mariadb",level:3},{value:"3. Open a new tab and start the Agones sidecar in local mode",id:"3-open-a-new-tab-and-start-the-agones-sidecar-in-local-mode",level:3},{value:"4. Start the server in database seed mode",id:"4-start-the-server-in-database-seed-mode",level:3},{value:"5. Local file server configuration (Optional)",id:"5-local-file-server-configuration-optional",level:3},{value:"6. Open two/three separate tabs and start the API server, instanceserver and client",id:"6-open-twothree-separate-tabs-and-start-the-api-server-instanceserver-and-client",level:3},{value:"7. In a browser, navigate to https://127.0.0.1:3000/location/default",id:"7-in-a-browser-navigate-to-https1270013000locationdefault",level:3}],p={toc:d},u="wrapper";function c(e){let{components:n,...t}=e;return(0,r.kt)(u,(0,a.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"advanced-setup"},"Advanced Setup"),(0,r.kt)("p",null,"If you want to setup Ethereal Engine docker instances, client, server, and/or\ninstance-server manually, follow these directions. The advanced setup is recommended\nfor all users, in order to understand more about everything that's going on."),(0,r.kt)("h3",{id:"1--install-your-dependencies"},"1. Install your dependencies"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd path/to/etherealengine\nnpm install\nnpm run dev-docker\nnpm run dev-reinit\n")),(0,r.kt)("p",null,"You should not need to use sudo in any case."),(0,r.kt)("p",null,"Error with mediasoup? ",(0,r.kt)("a",{parentName:"p",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"https://mediasoup.org/documentation/v3/mediasoup/installation/")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Check your version of python is up to date"),(0,r.kt)("li",{parentName:"ul"},"Ensure your install path has no whitespaces")),(0,r.kt)("h3",{id:"2-make-sure-you-have-a-mysql-database-installed-and-running----our-recommendation-is-mariadb"},"2. Make sure you have a mysql database installed and running -- our recommendation is Mariadb."),(0,r.kt)("p",null,"We've provided a docker container for easy setup:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd scripts && sudo bash start-db.sh\n")),(0,r.kt)("p",null,"This creates a Docker container of mariadb named etherealengine_db. You must have\ndocker installed on your machine for this script to work.\nIf you do not have Docker installed and do not wish to install it, you will have\nto manually create a MariaDB server."),(0,r.kt)("p",null,"The default username is 'server', the default password is 'password', the\ndefault database name is 'etherealengine', the default hostname is '127.0.0.1', and\nthe default port is ",(0,r.kt)("inlineCode",{parentName:"p"},"3306"),"."),(0,r.kt)("p",null,"Seeing errors connecting to the local DB? ",(0,r.kt)("strong",{parentName:"p"},"Try shutting off your local firewall.")),(0,r.kt)("h3",{id:"3-open-a-new-tab-and-start-the-agones-sidecar-in-local-mode"},"3. Open a new tab and start the Agones sidecar in local mode"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd scripts\nsudo bash start-agones.sh\n")),(0,r.kt)("p",null,"You can also go to vendor/agones/ and run"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"./sdk-server.linux.amd64 --local")),(0,r.kt)("p",null,"If you are using a Windows machine, run"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"sdk-server.windows.amd64.exe --local")),(0,r.kt)("p",null,"and for mac, run"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"./sdk-server.darwin.amd64 --local")),(0,r.kt)("h3",{id:"4-start-the-server-in-database-seed-mode"},"4. Start the server in database seed mode"),(0,r.kt)("p",null,"Several tables in the database need to be seeded with default values.\nRun ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-reinit")," or if on windows ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-reinit-windows"),"\nAfter several seconds, there should be no more logging.\nSome of the final lines should read like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"Server Ready\nExecuting (default): SET FOREIGN_KEY_CHECKS = 1\nServer EXIT\n")),(0,r.kt)("p",null,"At this point, the database has been seeded."),(0,r.kt)("h3",{id:"5-local-file-server-configuration-optional"},"5. Local file server configuration (Optional)"),(0,r.kt)("p",null,"If the .env.local file you have has the line\n",(0,r.kt)("inlineCode",{parentName:"p"},"STORAGE_PROVIDER=local"),"\nthen the scene editor will save components, models, scenes, etc. locally\n(as opposed to storing them on S3). You will need to start a local server\nto serve these files, and make sure that .env.local has the line\n",(0,r.kt)("inlineCode",{parentName:"p"},'LOCAL_STORAGE_PROVIDER="localhost:8642"'),".\nIn a new tab, go to ",(0,r.kt)("inlineCode",{parentName:"p"},"packages/server")," and run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run serve-local-files"),".\nThis will start up ",(0,r.kt)("inlineCode",{parentName:"p"},"http-server")," to serve files from ",(0,r.kt)("inlineCode",{parentName:"p"},"packages/server/upload"),"\non ",(0,r.kt)("inlineCode",{parentName:"p"},"localhost:8642"),".\nYou may have to accept the invalid self-signed certificate for it in the browser;\nsee 'Allow local file http-server connection with invalid certificate' below."),(0,r.kt)("h3",{id:"6-open-twothree-separate-tabs-and-start-the-api-server-instanceserver-and-client"},"6. Open two/three separate tabs and start the API server, instanceserver and client"),(0,r.kt)("p",null,"In /packages/server, run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev")," which will launch the api server, world server, media server and file server.\nIf you are not using instanceservers, you can instead run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-api-server")," in the api server.\nIn the final tab, go to /packages/client and run ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev"),".\nIf you are on windows you need to use ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev-windows")," instead of ",(0,r.kt)("inlineCode",{parentName:"p"},"npm run dev"),"."),(0,r.kt)("h3",{id:"7-in-a-browser-navigate-to-https1270013000locationdefault"},"7. In a browser, navigate to ",(0,r.kt)("a",{parentName:"h3",href:"https://127.0.0.1:3000/location/default"},"https://127.0.0.1:3000/location/default")),(0,r.kt)("p",null,"The database seeding process creates a default empty location called 'default'.\nIt can be navigated to by going to '",(0,r.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default'"},"https://127.0.0.1:3000/location/default'"),".\nAs of this writing, the cert provided in the ethereal engine package for local use is\nnot adequately signed. You can create signed certificates and replace the\ndefault ones, but most developers just ignore the warnings. Browsers will throw\nup warnings about going to insecure pages. You should be able to tell the browser\nto ignore it, usually by clicking on some sort of 'advanced options' button or\nlink and then something along the lines of 'go there anyway'."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/d88112b6.0781129c.js b/es/assets/js/d88112b6.0781129c.js new file mode 100644 index 000000000000..fc64139ce234 --- /dev/null +++ b/es/assets/js/d88112b6.0781129c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[176],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>b});var r=n(7294);function s(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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){s(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,s=function(e,t){if(null==e)return{};var n,r,s={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var i=r.createContext({}),c=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(i.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,s=e.mdxType,a=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=s,b=p["".concat(i,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(b,o(o({ref:t},u),{},{components:n})):r.createElement(b,o({ref:t},u))}));function b(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var a=n.length,o=new Array(a);o[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[p]="string"==typeof e?e:s,o[1]=l;for(var c=2;c<a;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},6792:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(7462),s=(n(7294),n(3905));const a={},o="Cluster Management",l={unversionedId:"host/devops_deployment/managing_remote_kubernetes",id:"host/devops_deployment/managing_remote_kubernetes",title:"Cluster Management",description:"Kubernetes Web UI (Dashboard)",source:"@site/docs/1_host/2_devops_deployment/5_managing_remote_kubernetes.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/managing_remote_kubernetes",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/5_managing_remote_kubernetes.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"How to set up GitHub to install external projects",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects"},next:{title:"Release Helm Chart",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart"}},i={},c=[{value:"Kubernetes Web UI (Dashboard)",id:"kubernetes-web-ui-dashboard",level:2},{value:"Install Lens",id:"install-lens",level:2},{value:"AWS",id:"aws",level:4}],u={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,s.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"cluster-management"},"Cluster Management"),(0,s.kt)("h2",{id:"kubernetes-web-ui-dashboard"},"Kubernetes Web UI (Dashboard)"),(0,s.kt)("p",null,"Dashboard is a web-based Kubernetes user interface. You can use Dashboard to deploy containerized applications to a Kubernetes cluster, troubleshoot your containerized application, and manage the cluster resources."),(0,s.kt)("p",null,(0,s.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/"},"https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/")),(0,s.kt)("h2",{id:"install-lens"},"Install Lens"),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"sudo snap install kontena-lens --classic")),(0,s.kt)("p",null,"Add the K8 cluster using kubectl\n",(0,s.kt)("a",{parentName:"p",href:"https://docs.k8slens.dev/v4.1.4/clusters/adding-clusters/"},"https://docs.k8slens.dev/v4.1.4/clusters/adding-clusters/")),(0,s.kt)("p",null,"Add kubernetes lens prometheus support if not already installed\n",(0,s.kt)("a",{parentName:"p",href:"https://docs.k8slens.dev/v4.1.4/extensions/usage/"},"https://docs.k8slens.dev/v4.1.4/extensions/usage/")),(0,s.kt)("h4",{id:"aws"},"AWS"),(0,s.kt)("p",null,"AWS credentials with EKS and Cluster permissions required"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/dcc1f912.b4a1ef2a.js b/es/assets/js/dcc1f912.b4a1ef2a.js new file mode 100644 index 000000000000..15e213daab1d --- /dev/null +++ b/es/assets/js/dcc1f912.b4a1ef2a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3666],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var a=n(7294);function l(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 i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){l(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,l=function(e,t){if(null==e)return{};var n,a,l={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(p.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,l=e.mdxType,r=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=s(n),c=l,h=u["".concat(p,".").concat(c)]||u[c]||m[c]||r;return n?a.createElement(h,i(i({ref:t},d),{},{components:n})):a.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,i=new Array(r);i[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[u]="string"==typeof e?e:l,i[1]=o;for(var s=2;s<r;s++)i[s]=n[s];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},1100:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=n(7462),l=(n(7294),n(3905));const r={},i="Upgrading Helm Release",o={unversionedId:"host/devops_deployment/upgrade_helm_deployment",id:"host/devops_deployment/upgrade_helm_deployment",title:"Upgrading Helm Release",description:"This guide will cover various sections regarding upgrading an existing helm deployment.",source:"@site/docs/1_host/2_devops_deployment/7_upgrade_helm_deployment.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/upgrade_helm_deployment",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/7_upgrade_helm_deployment.md",tags:[],version:"current",sidebarPosition:7,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Release Helm Chart",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart"},next:{title:"Tutorials",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/"}},p={},s=[{value:"Getting Updated <code>values.yaml</code> File",id:"getting-updated-valuesyaml-file",level:2},{value:"Evaluating Difference in <code>value.yaml</code> & Deployed Charts",id:"evaluating-difference-in-valueyaml--deployed-charts",level:2},{value:"Upgrading Helm Deployment",id:"upgrading-helm-deployment",level:2}],d={toc:s},u="wrapper";function m(e){let{components:t,...n}=e;return(0,l.kt)(u,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"upgrading-helm-release"},"Upgrading Helm Release"),(0,l.kt)("p",null,"This guide will cover various sections regarding upgrading an existing helm deployment."),(0,l.kt)("h2",{id:"getting-updated-valuesyaml-file"},"Getting Updated ",(0,l.kt)("inlineCode",{parentName:"h2"},"values.yaml")," File"),(0,l.kt)("p",null,"Usually a helm release upgrade is required when changes are made in configuration of helm charts. To do so first thing required is ",(0,l.kt)("inlineCode",{parentName:"p"},"value.yaml")," file of current configuration. If you already have an updated copy of this file then you can update the desired values and push the changes to helm deployment."),(0,l.kt)("p",null,"But for scenarios where multiple people are working same deployment, it becomes difficult to maintain updated ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file. At anytime you can get the current version/snapshot of ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file by running ",(0,l.kt)("a",{parentName:"p",href:"https://helm.sh/docs/helm/helm_get_values/"},"get values")," command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm get values [DEPLOYMENT_NAME]\n")),(0,l.kt)("p",null,"i.e."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm get values dev\n")),(0,l.kt)("p",null,"You can save the output in a ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file and update the required values."),(0,l.kt)("h2",{id:"evaluating-difference-in-valueyaml--deployed-charts"},"Evaluating Difference in ",(0,l.kt)("inlineCode",{parentName:"h2"},"value.yaml")," & Deployed Charts"),(0,l.kt)("p",null,"It become very handy if you can evaluate the differences between your local ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file and current deployment. This way you can beforehand visualize the changes a helm upgrade is going to make. To do so first make sure you have ",(0,l.kt)("inlineCode",{parentName:"p"},"helm diff")," plugin installed. You can install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm plugin install https://github.com/databus23/helm-diff\n")),(0,l.kt)("p",null,"Once ",(0,l.kt)("inlineCode",{parentName:"p"},"helm diff")," plugin is installed then you can run following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm diff upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --values [PATH_TO_VALUES_YAML]\n")),(0,l.kt)("p",null,"i.e."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm diff upgrade dev etherealengine/etherealengine --values ~/etherealengine-ops/values/dev.ethereal.values.yaml\n")),(0,l.kt)("p",null,"This will print the output of differences between deployed helm release and changes in specified ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file. Incase the output is empty, it means there is no difference/changes."),(0,l.kt)("h2",{id:"upgrading-helm-deployment"},"Upgrading Helm Deployment"),(0,l.kt)("p",null,"Once the local ",(0,l.kt)("inlineCode",{parentName:"p"},"values.yaml")," file is updated, it can be reflect to deployment using following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --reuse-values -f [PATH_TO_VALUES_YAML]\n")),(0,l.kt)("p",null,"i.e."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade dev etherealengine/etherealengine --reuse-values -f ~/etherealengine-ops/values/dev.ethereal.values.yaml\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/e988a1b0.98fbbb7a.js b/es/assets/js/e988a1b0.98fbbb7a.js new file mode 100644 index 000000000000..059192b1525d --- /dev/null +++ b/es/assets/js/e988a1b0.98fbbb7a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4705],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});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 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 l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",h={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,o=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),u=c(n),p=a,m=u["".concat(s,".").concat(p)]||u[p]||h[p]||o;return n?r.createElement(m,l(l({ref:t},d),{},{components:n})):r.createElement(m,l({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=p;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:a,l[1]=i;for(var c=2;c<o;c++)l[c]=n[c];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},9128:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={},l="Old Docker Instructions",i={unversionedId:"host/installation/docker",id:"host/installation/docker",title:"Old Docker Instructions",description:"You can quickstart locally using docker, if you don't have node installed or",source:"@site/docs/1_host/1_installation/7_docker.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/docker",permalink:"/etherealengine-docs/es/docs/host/installation/docker",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/7_docker.md",tags:[],version:"current",sidebarPosition:7,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Troubleshooting",permalink:"/etherealengine-docs/es/docs/host/installation/install_troubleshooting"},next:{title:"Logging with Opensearch on Docker",permalink:"/etherealengine-docs/es/docs/host/installation/opensearch"}},s={},c=[{value:"Get local IP address",id:"get-local-ip-address",level:2},{value:"Start local databases",id:"start-local-databases",level:2},{value:"Build the image",id:"build-the-image",level:2},{value:"Run the server to seed the database, wait a couple minutes, then delete it",id:"run-the-server-to-seed-the-database-wait-a-couple-minutes-then-delete-it",level:2},{value:"Run the images",id:"run-the-images",level:2},{value:"Delete containers, if you want to run a new build, or just get rid of them",id:"delete-containers-if-you-want-to-run-a-new-build-or-just-get-rid-of-them",level:2}],d={toc:c},u="wrapper";function h(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"old-docker-instructions"},"Old Docker Instructions"),(0,a.kt)("p",null,"You can quickstart locally using docker, if you don't have node installed or\njust want to test the latest."),(0,a.kt)("h2",{id:"get-local-ip-address"},"Get local IP address"),(0,a.kt)("p",null,"Use a tool like ",(0,a.kt)("inlineCode",{parentName:"p"},"ifconfig")," to get your local IP address."),(0,a.kt)("h2",{id:"start-local-databases"},"Start local databases"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd scripts\ndocker-compose up\n")),(0,a.kt)("p",null,"When the logging stops, that indicates that the databases have been created and\nare running."),(0,a.kt)("p",null,"Ctrl+c out of that, then from scripts run ",(0,a.kt)("inlineCode",{parentName:"p"},"./start-all-docker.sh"),"\n(This must be run every time you start your machine anew)"),(0,a.kt)("h2",{id:"build-the-image"},"Build the image"),(0,a.kt)("p",null,"Create an empty folder at the root called ",(0,a.kt)("inlineCode",{parentName:"p"},"project-package-jsons")," and then run\nthe following command to build:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'DOCKER_BUILDKIT=1 docker build -t etherealengine --build-arg MYSQL_USER=server \\\n --build-arg MYSQL_PASSWORD=password --build-arg MYSQL_HOST=127.0.0.1 \\\n --build-arg MYSQL_DATABASE=etherealengine --build-arg MYSQL_PORT=3304 \\\n --build-arg VITE_SERVER_HOST=localhost --build-arg VITE_SERVER_PORT=3030 \\\n --build-arg VITE_INSTANCESERVER_HOST=localhost --build-arg VITE_INSTANCESERVER_PORT=3031 \\\n --build-arg VITE_LOCAL_BUILD=true --build-arg CACHE_DATE="$(date)" --network="host" .\n')),(0,a.kt)("h2",{id:"run-the-server-to-seed-the-database-wait-a-couple-minutes-then-delete-it"},"Run the server to seed the database, wait a couple minutes, then delete it"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "FORCE_DB_REFRESH=true" --network host etherealengine\ndocker logs server -f\n-Wait for the line "Server Ready", then Ctrl+c out of the logs-\ndocker container stop server\ndocker container rm server\n')),(0,a.kt)("h2",{id:"run-the-images"},"Run the images"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'docker run -d --name serve-local --env-file .env.local.default -e "SERVER_MODE=serve-local" --network host etherealengine\ndocker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine\ndocker run -d --name client --env-file .env.local.default -e "SERVER_MODE=client" --network host etherealengine\ndocker run -d --name world --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine\ndocker run -d --name channel --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" -e "INSTANCESERVER_PORT=3032" --network host etherealengine\n')),(0,a.kt)("h2",{id:"delete-containers-if-you-want-to-run-a-new-build-or-just-get-rid-of-them"},"Delete containers, if you want to run a new build, or just get rid of them"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"docker container stop serve-local\ndocker container rm serve-local\ndocker container stop server\ndocker container rm server\ndocker container stop client\ndocker container rm client\ndocker container stop world\ndocker container rm world\ndocker container stop channel\ndocker container rm channel\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/ea08158a.3b7ce41d.js b/es/assets/js/ea08158a.3b7ce41d.js new file mode 100644 index 000000000000..e361799a24cb --- /dev/null +++ b/es/assets/js/ea08158a.3b7ce41d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[4995],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function 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 o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=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):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},h="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),h=p(n),d=i,m=h["".concat(s,".").concat(d)]||h[d]||c[d]||l;return n?a.createElement(m,o(o({ref:t},u),{},{components:n})):a.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,o=new Array(l);o[0]=d;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[h]="string"==typeof e?e:i,o[1]=r;for(var p=2;p<l;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}d.displayName="MDXCreateElement"},4501:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>u});var a=n(7462),i=(n(7294),n(3905)),l=n(4401);const o={},r="Ethereal Engine on Minikube",s={unversionedId:"host/devops_deployment/minikube",id:"host/devops_deployment/minikube",title:"Ethereal Engine on Minikube",description:"Install kubectl, Helm, Docker, and VirtualBox",source:"@site/docs/1_host/2_devops_deployment/1_minikube.md",sourceDirName:"1_host/2_devops_deployment",slug:"/host/devops_deployment/minikube",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/minikube",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/2_devops_deployment/1_minikube.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal Engine on Docker Desktop",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop"},next:{title:"Ethereal Engine on AWS",permalink:"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup"}},p={},u=[{value:"Install kubectl, Helm, Docker, and VirtualBox",id:"install-kubectl-helm-docker-and-virtualbox",level:2},{value:"Download and install minikube",id:"download-and-install-minikube",level:2},{value:"Clone Ethereal Engine repo to your local machine",id:"clone-ethereal-engine-repo-to-your-local-machine",level:2},{value:"Start MinIO & MariaDB server locally via Docker",id:"start-minio--mariadb-server-locally-via-docker",level:2},{value:"Create minikube cluster",id:"create-minikube-cluster",level:2},{value:"Starting ingress after minikube has started",id:"starting-ingress-after-minikube-has-started",level:3},{value:"Get minikube IP address and edit system hostfile to point to",id:"get-minikube-ip-address-and-edit-system-hostfile-to-point-to",level:2},{value:"Add Helm repos",id:"add-helm-repos",level:2},{value:"Install Agones and Redis deployments",id:"install-agones-and-redis-deployments",level:2},{value:"Install Elastic Search and Kibana using Helm for Server Logs",id:"install-elastic-search-and-kibana-using-helm-for-server-logs",level:2},{value:"Run build_minikube.sh",id:"run-build_minikubesh",level:2},{value:"Update Helm Values File",id:"update-helm-values-file",level:2},{value:"Deploy Ethereal Engine Helm chart",id:"deploy-ethereal-engine-helm-chart",level:2},{value:"Accept invalid certs",id:"accept-invalid-certs",level:2}],h={toc:u},c="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(c,(0,a.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"ethereal-engine-on-minikube"},"Ethereal Engine on Minikube"),(0,i.kt)("h2",{id:"install-kubectl-helm-docker-and-virtualbox"},"Install kubectl, Helm, Docker, and VirtualBox"),(0,i.kt)("p",null,"If ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/tools/"},"kubectl"),", ",(0,i.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/install/"},"Helm"),",\n",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/get-docker/"},"Docker")," and/or ",(0,i.kt)("a",{parentName:"p",href:"https://www.virtualbox.org/wiki/Downloads"},"VirtualBox"),"\naren't already installed on your machine, install them."),(0,i.kt)("p",null,"You may also need to install ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install/"},"Docker Compose")),(0,i.kt)("h2",{id:"download-and-install-minikube"},"Download and install minikube"),(0,i.kt)("p",null,"Instructions can be found ",(0,i.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/start/"},"here")),(0,i.kt)("p",null,"While you can follow the demo instructions there about starting minikube, deploying\nsome demo deployments, etc. to get a feel for it, before deploying Ethereal Engine you should delete\nyour minikube cluster, since we have some specific starting requirements."),(0,i.kt)("h2",{id:"clone-ethereal-engine-repo-to-your-local-machine"},"Clone Ethereal Engine repo to your local machine"),(0,i.kt)("p",null,"To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local\nservices, you'll need to get the Ethereal Engine repo on your machine. This is most easily\ndone by running ",(0,i.kt)("inlineCode",{parentName:"p"},"git clone https://github.com/etherealengine/etherealengine.git")),(0,i.kt)("h2",{id:"start-minio--mariadb-server-locally-via-docker"},"Start MinIO & MariaDB server locally via Docker"),(0,i.kt)("p",null,"For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s."),(0,i.kt)("p",null,"If you run ",(0,i.kt)("inlineCode",{parentName:"p"},"docker-compose up")," from the top-level ",(0,i.kt)("inlineCode",{parentName:"p"},"/scripts")," directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running ",(0,i.kt)("inlineCode",{parentName:"p"},"npm run dev-docker"),"."),(0,i.kt)("p",null,"Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ",(0,i.kt)("inlineCode",{parentName:"p"},"./scripts/build_minikube.sh"),"."),(0,i.kt)("h2",{id:"create-minikube-cluster"},"Create minikube cluster"),(0,i.kt)("p",null,"Run the following command:\n",(0,i.kt)("inlineCode",{parentName:"p"},"minikube start --disk-size 40000m --cpus 4 --memory 10124m --addons ingress --driver virtualbox")),(0,i.kt)("p",null,"This says to start minikube with 40GB of disk space, 4 CPUs, 10GB of memory, using VirtualBox as its\ndriver, and starting up an nginx ingress service."),(0,i.kt)("p",null,"The disk space, CPUs, and memory allocation are configurable. These are what we recommend for optimal\nrunning (though the disk space might be a bit more than necessary). When minikube is running,\nit will reserve those resources for itself regardless of whether the services in minikube are using\nthat much."),(0,i.kt)("p",null,"The 10GB of memory might be the spec with the least wiggle room. Later instructions on building\nthe Docker image will have it be built in the minikube context. This uses the RAM reserved for minikube,\nand the client build process normally uses about 8GB of RAM at its peak. minikube may freeze if\nit gets maxed out on RAM, and the Docker build process might freeze indefinitely."),(0,i.kt)("h3",{id:"starting-ingress-after-minikube-has-started"},"Starting ingress after minikube has started"),(0,i.kt)("p",null,"If you forget to use ",(0,i.kt)("inlineCode",{parentName:"p"},"--addons ingress")," when starting minikube, you can start nginx later by\nrunning ",(0,i.kt)("inlineCode",{parentName:"p"},"minikube addons enable ingress")),(0,i.kt)("h2",{id:"get-minikube-ip-address-and-edit-system-hostfile-to-point-to"},"Get minikube IP address and edit system hostfile to point to"),(0,i.kt)("p",null,"Run this command after minikube has started: ",(0,i.kt)("inlineCode",{parentName:"p"},"minikube ip"),"\nThis will get you the address that minikube is running on."),(0,i.kt)("p",null,"You'll need to edit your hostfile to point certain domains to minikube IP addresses. On Linux,\nthis is done by running ",(0,i.kt)("inlineCode",{parentName:"p"},"sudo gedit /etc/hosts"),"."),(0,i.kt)("p",null,"Add the following lines:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-conf"},"<Output of 'minikube ip'> local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org\n10.0.2.2 host.minikube.internal\n")),(0,i.kt)("p",null,"The first line says to point several *-local.etherealengine.org domains internally to the minikube cluster,\nwhere the nginx ingress server will redirect the traffic to the appropriate pod.\nThe second line is used to give minikube access to your local environment, particularly so that it\ncan access the MariaDB server."),(0,i.kt)("p",null,"Make sure to save this file after you've edited it. On Linux, at least, you need root permissions\nto edit it."),(0,i.kt)("h2",{id:"add-helm-repos"},"Add Helm repos"),(0,i.kt)("p",null,"You'll need to add a few Helm repos. Run the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add agones https://agones.dev/chart/stable\nhelm repo add redis https://charts.bitnami.com/bitnami\nhelm repo add etherealengine https://helm.etherealengine.org\n")),(0,i.kt)("p",null,"This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively."),(0,i.kt)("h2",{id:"install-agones-and-redis-deployments"},"Install Agones and Redis deployments"),(0,i.kt)("p",null,"After adding those Helm repos, you'll start installing deployments using Helm repos."),(0,i.kt)("p",null,"Make sure that kubectl is pointed at minikube by running ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl config current-context"),",\nwhich should say 'minikube'. You can also run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl config get-contexts")," to get all contexts\nthat kubectl has been configured to run; the current one will have a '*' under the left-most\n'current' column."),(0,i.kt)("p",null,"Once kubectl is pointed to minikube, from the top of the Ethereal Engine repo, run\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/agones-default-values.yaml> agones agones/agones")," to install Agones\nand ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install local-redis redis/redis")," to install redis."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/agones-default-values.yaml"},"agones-default-values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("p",null,"You can run ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods -A")," to list all of the pods running in minikube. After a minute or so,\nall of these pods should be in the Running state."),(0,i.kt)("h2",{id:"install-elastic-search-and-kibana-using-helm-for-server-logs"},"Install Elastic Search and Kibana using Helm for Server Logs"),(0,i.kt)("p",null,"To install Elasticsearch, add the elastic repository in Helm: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm repo add elastic https://helm.elastic.co")),(0,i.kt)("p",null,"Now, use the curl command to download the values.yaml file containing configuration information:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml")),(0,i.kt)("p",null,"Use the helm install command and the values.yaml file to install the Elasticsearch helm chart: "),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -f ./values.yaml")),(0,i.kt)("p",null,"The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml")),(0,i.kt)("p",null,"Now check if the cluster members are up: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods --namespace=default -l app=elasticsearch-master -w")),(0,i.kt)("p",null,"The other option is to use the helm test command to examine the cluster\u2019s health: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm test elasticsearch")),(0,i.kt)("p",null,"To install Kibana on top of Elasticsearch : ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install kibana elastic/kibana")),(0,i.kt)("p",null,"Check if all the pods are ready: ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods")),(0,i.kt)("p",null,"After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"http://localhost:5601")," in your browser"),(0,i.kt)("p",null,"In order to connect logger with elasticsearch, update ",(0,i.kt)("inlineCode",{parentName:"p"},"local.minikube.template.values.yaml")," env ",(0,i.kt)("inlineCode",{parentName:"p"},"api.extraEnv.ELASTIC_HOST")," for e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"http://<username>:<password>@<host>:<port>")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.minikube.template.values.yaml"},"local.minikube.template.values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("h2",{id:"run-build_minikubesh"},"Run build_minikube.sh"),(0,i.kt)("p",null,"When minikube is running, run the following command from the root of the Ethereal Engine repo:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./scripts/build_minikube.sh\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"If you face issue related to ",(0,i.kt)("inlineCode",{parentName:"p"},'"packages/projects/projects/" does not exist')," then run following commands in your terminal:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"export MYSQL_HOST=localhost\nnpm run dev-docker\nnpm run dev-reinit\nnpm run install-projects\n")),(0,i.kt)("p",null,"This points Docker ",(0,i.kt)("em",{parentName:"p"},"in the current terminal")," to minikube's Docker environment. Anything that Docker builds\nwill be locally accessible to minikube; if the first main command in the script were not run, Docker would build to your\nmachine's Docker environment, and minikube would not have access to it."),(0,i.kt)("p",null,"The script also builds the full-repo Docker image using several build arguments. Vite, which builds\nthe client files, uses some information from the MariaDB database created for minikube deployments\nto fill in some variables, and needs database credentials. The script will supply default values\nfor all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST,\nVITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your minikube deployment\naccessible on ",(0,i.kt)("inlineCode",{parentName:"p"},"(local/api-local/instanceserver-local).etherealengine.org"),"; if you want to run it on a different\ndomain, then you'll have to set those three environment variables to what you want them to be (and also\nchange the hostfile records you made pointing those subdomains to minikube's IP)"),(0,i.kt)("p",null,"This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for\ndifferent services, it will only run the parts needed for that service. This may take up to 15 minutes,\nthough later builds should take less time as things are cached."),(0,i.kt)("h2",{id:"update-helm-values-file"},"Update Helm Values File"),(0,i.kt)("p",null,"This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is\na ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/local.minikube.template.values.yaml"},"template")," for this file in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo."),(0,i.kt)("p",null,"If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable ",(0,i.kt)("inlineCode",{parentName:"p"},"api.fileServer.hostUploadFolder")," with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. Its mandatory to point to ",(0,i.kt)("inlineCode",{parentName:"p"},"/packages/server/upload")," folder of your engine folder."),(0,i.kt)("h2",{id:"deploy-ethereal-engine-helm-chart"},"Deploy Ethereal Engine Helm chart"),(0,i.kt)("p",null,"Run the following command: ",(0,i.kt)("inlineCode",{parentName:"p"},"helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine"),"."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-true.values.yaml"},"db-refresh-true.values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("p",null,"After a minute or so, running ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get pods")," should show one or more instanceservers, one or more api\nservers, and one client server in the Running state. Setting ",(0,i.kt)("inlineCode",{parentName:"p"},"FORCE_DB_REFRESH=true")," made the api servers\n(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run\n",(0,i.kt)("inlineCode",{parentName:"p"},"helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine"),".\nThe API pods will restart and will now not attempt to reinit the database on boot."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops/blob/master/configs/db-refresh-false.values.yaml"},"db-refresh-false.values.yaml")," can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ethereal-engine-ops"},"ethereal-engine-ops")," repo.")),(0,i.kt)("h2",{id:"accept-invalid-certs"},"Accept invalid certs"),(0,i.kt)(l.ZP,{mdxType:"AcceptCertificates"}))}d.isMDXComponent=!0},4401:(e,t,n)=>{n.d(t,{ZP:()=>r});var a=n(7462),i=(n(7294),n(3905));const l={toc:[]},o="wrapper";function r(e){let{components:t,...n}=e;return(0,i.kt)(o,(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application."),(0,i.kt)("p",null,"Go to ",(0,i.kt)("a",{parentName:"p",href:"https://local.etherealengine.org/"},"https://local.etherealengine.org/"),", you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"wss://api-local.etherealengine.org -> ",(0,i.kt)("a",{parentName:"li",href:"https://api-local.etherealengine.org"},"https://api-local.etherealengine.org")),(0,i.kt)("li",{parentName:"ul"},"wss://instanceserver-local.etherealengine.org -> ",(0,i.kt)("a",{parentName:"li",href:"https://instanceserver-local.etherealengine.org"},"https://instanceserver-local.etherealengine.org")),(0,i.kt)("li",{parentName:"ul"},"https://localhost:9000")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)")))}r.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/es/assets/js/ebc45004.77289e03.js b/es/assets/js/ebc45004.77289e03.js new file mode 100644 index 000000000000..814c0916069f --- /dev/null +++ b/es/assets/js/ebc45004.77289e03.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[5194,3179],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),u=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=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=u(n),h=i,m=c["".concat(s,".").concat(h)]||c[h]||p[h]||o;return n?a.createElement(m,r(r({ref:t},d),{},{components:n})):a.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var u=2;u<o;u++)r[u]=n[u];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},8192:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905)),o=n(932);const r={},l="Basic Setup",s={unversionedId:"host/installation/basic_setup",id:"host/installation/basic_setup",title:"Basic Setup",description:"",source:"@site/docs/1_host/1_installation/1_basic_setup.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/basic_setup",permalink:"/etherealengine-docs/es/docs/host/installation/basic_setup",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/1_basic_setup.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Installation",permalink:"/etherealengine-docs/es/docs/host/installation/"},next:{title:"Installing on Mac OS X",permalink:"/etherealengine-docs/es/docs/host/installation/mac_os_x"}},u={},d=[],c={toc:d},p="wrapper";function h(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"basic-setup"},"Basic Setup"),(0,i.kt)(o.default,{mdxType:"Readme"}))}h.isMDXComponent=!0},932:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var a=n(7462),i=(n(7294),n(3905));const o={},r="Installation",l={unversionedId:"host/installation/readme",id:"host/installation/readme",title:"Installation",description:"Getting up and running requires just a few steps, but this can be tricky,",source:"@site/docs/1_host/1_installation/readme.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/",permalink:"/etherealengine-docs/es/docs/host/installation/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal for Hosts",permalink:"/etherealengine-docs/es/docs/host/"},next:{title:"Basic Setup",permalink:"/etherealengine-docs/es/docs/host/installation/basic_setup"}},s={},u=[{value:"Pre-Install Checklist",id:"pre-install-checklist",level:2},{value:"Clone the repository",id:"clone-the-repository",level:3},{value:"Ensure you are running Node 16 or 18",id:"ensure-you-are-running-node-16-or-18",level:3},{value:"Docker is your friend",id:"docker-is-your-friend",level:3},{value:"Quick Start",id:"quick-start",level:2},{value:"Accept Certificates",id:"accept-certificates",level:3},{value:"Admin System and User Setup",id:"admin-system-and-user-setup",level:3},{value:"Alternate Method:",id:"alternate-method",level:4},{value:"Advanced Installation and Troubleshooting",id:"advanced-installation-and-troubleshooting",level:2}],d={toc:u},c="wrapper";function p(e){let{components:t,...o}=e;return(0,i.kt)(c,(0,a.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"installation"},"Installation"),(0,i.kt)("p",null,"Getting up and running requires just a few steps, but this can be tricky,\ndepending on your platform and current environment. Please follow the directions\nfor your environment."),(0,i.kt)("h2",{id:"pre-install-checklist"},"Pre-Install Checklist"),(0,i.kt)("ul",{className:"contains-task-list"},(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Clone the repository"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Node.js 16 or 18 (earlier versions not guaranteed to work)"),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Python >=3.6 + ",(0,i.kt)("a",{parentName:"li",href:"https://pypi.org/project/pip/"},"PIP"),", C++, and\nother build tools. See the ",(0,i.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup install instructions"),"\nfor full details."),(0,i.kt)("li",{parentName:"ul",className:"task-list-item"},(0,i.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Docker",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"(Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's ",(0,i.kt)("inlineCode",{parentName:"li"},".env.local")," accordingly.")))),(0,i.kt)("p",null,"You should now be ready to follow the ",(0,i.kt)("a",{parentName:"p",href:"#quick-start"},"Quick Start")," instructions."),(0,i.kt)("h3",{id:"clone-the-repository"},"Clone the repository"),(0,i.kt)("p",null,"A lot has changed during development, and our monorepo has gotten quite large.\nTo avoid cloning the entire thing, use this command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"git clone https://github.com/etherealengine/etherealengine --depth 1\n")),(0,i.kt)("h3",{id:"ensure-you-are-running-node-16-or-18"},"Ensure you are running Node 16 or 18"),(0,i.kt)("p",null,"The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions\nare not guaranteed to work properly."),(0,i.kt)("p",null,"A version manager can be helpful for this:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"NodeJS only: ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/nvm-sh/nvm"},"NVM")),(0,i.kt)("li",{parentName:"ul"},"Polyglot: ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/asdf-vm/asdf"},"ASDF"))),(0,i.kt)("p",null,"Before running the engine, please check ",(0,i.kt)("inlineCode",{parentName:"p"},"node --version"),"\nIf you are using a node version below 16, please update or nothing will work.\nYou will know you are having issues if you try to install at root and are\ngetting dependency errors."),(0,i.kt)("h3",{id:"docker-is-your-friend"},"Docker is your friend"),(0,i.kt)("p",null,"You don't need to use ",(0,i.kt)("a",{parentName:"p",href:"https://docs.docker.com/"},"Docker"),", but it will make\nyour life much easier.\nIf you don't wish to use Docker, you will need to setup mariadb and redis on\nyour machine. You can find credentials in ",(0,i.kt)("inlineCode",{parentName:"p"},"/scripts/docker-compose.yml")),(0,i.kt)("h2",{id:"quick-start"},"Quick Start"),(0,i.kt)("p",null,"If you are lucky, this will just work. However, you may encounter some\nissues. Make sure you are running Node 16, and check your dependencies."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd path/to/etherealengine\ncp .env.local.default .env.local\nnpm install\nnpm run dev-docker\nnpm run dev-reinit\nnpm run dev\n")),(0,i.kt)("p",null,"Now run Ethereal Engine in browser by navigating to ",(0,i.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default"},"this link"),". "),(0,i.kt)("h3",{id:"accept-certificates"},"Accept Certificates"),(0,i.kt)("p",null,"You'll have to tell your browser to ignore the insecure connections when you try to load the website."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates."),(0,i.kt)("li",{parentName:"ol"},"Open Developer tools in your browser by clicking the side menu with three dots, then ",(0,i.kt)("inlineCode",{parentName:"li"},"More tools > Developer tools")," (or use ",(0,i.kt)("inlineCode",{parentName:"li"},"Ctrl+Shift+I"),") and then go to the 'Console' tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab."),(0,i.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.")),(0,i.kt)("h3",{id:"admin-system-and-user-setup"},"Admin System and User Setup"),(0,i.kt)("p",null,"You can administrate many features from the admin panel at https://localhost:3000/admin"),(0,i.kt)("p",null,"To make a user an admin, open a page and open the profile menu. There is a button labelled ",(0,i.kt)("inlineCode",{parentName:"p"},"Show User ID"),"\nwhich opens a text field with your userId. Paste it in and run the following command in\nyour terminal:"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id={COPIED_USER_ID}")),(0,i.kt)("p",null,"Example:\n",(0,i.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac")),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"image",src:n(2288).Z,width:"596",height:"294"})),(0,i.kt)("h4",{id:"alternate-method"},"Alternate Method:"),(0,i.kt)("p",null,"Look up in User table and change userRole to 'admin'\n(It helps to use a graphical database explorer, we recommend ",(0,i.kt)("a",{parentName:"p",href:"https://beekeeperstudio.io/"},"beekeeperstudio.io"),")"),(0,i.kt)("p",null,"Test user Admin privileges by going to ",(0,i.kt)("inlineCode",{parentName:"p"},"/admin")),(0,i.kt)("h2",{id:"advanced-installation-and-troubleshooting"},"Advanced Installation and Troubleshooting"),(0,i.kt)("p",null,"If you run into any trouble with the Quick Start instructions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Please make sure you've followed the\n",(0,i.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup installation instructions")),(0,i.kt)("li",{parentName:"ul"},"Check your OS-specific instructions:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/windows"},"Installing on Windows (10+)")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/mac_os_x"},"Installing on Mac OS X")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/install_troubleshooting"},"Installation Troubleshooting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/advanced_setup"},"Advanced Setup")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://vitejs.dev/guide/troubleshooting.html#dev-server"},"Vite dev server is stalling"))))}p.isMDXComponent=!0},2288:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png"}}]); \ No newline at end of file diff --git a/es/assets/js/f7429bc1.67e41e76.js b/es/assets/js/f7429bc1.67e41e76.js new file mode 100644 index 000000000000..5a3e28fb0336 --- /dev/null +++ b/es/assets/js/f7429bc1.67e41e76.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3179],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});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<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=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},d=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=u(n),h=r,m=p["".concat(s,".").concat(h)]||p[h]||c[h]||i;return n?a.createElement(m,o(o({ref:t},d),{},{components:n})):a.createElement(m,o({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var u=2;u<i;u++)o[u]=n[u];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},932:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(7462),r=(n(7294),n(3905));const i={},o="Installation",l={unversionedId:"host/installation/readme",id:"host/installation/readme",title:"Installation",description:"Getting up and running requires just a few steps, but this can be tricky,",source:"@site/docs/1_host/1_installation/readme.md",sourceDirName:"1_host/1_installation",slug:"/host/installation/",permalink:"/etherealengine-docs/es/docs/host/installation/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/1_host/1_installation/readme.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Ethereal for Hosts",permalink:"/etherealengine-docs/es/docs/host/"},next:{title:"Basic Setup",permalink:"/etherealengine-docs/es/docs/host/installation/basic_setup"}},s={},u=[{value:"Pre-Install Checklist",id:"pre-install-checklist",level:2},{value:"Clone the repository",id:"clone-the-repository",level:3},{value:"Ensure you are running Node 16 or 18",id:"ensure-you-are-running-node-16-or-18",level:3},{value:"Docker is your friend",id:"docker-is-your-friend",level:3},{value:"Quick Start",id:"quick-start",level:2},{value:"Accept Certificates",id:"accept-certificates",level:3},{value:"Admin System and User Setup",id:"admin-system-and-user-setup",level:3},{value:"Alternate Method:",id:"alternate-method",level:4},{value:"Advanced Installation and Troubleshooting",id:"advanced-installation-and-troubleshooting",level:2}],d={toc:u},p="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(p,(0,a.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"installation"},"Installation"),(0,r.kt)("p",null,"Getting up and running requires just a few steps, but this can be tricky,\ndepending on your platform and current environment. Please follow the directions\nfor your environment."),(0,r.kt)("h2",{id:"pre-install-checklist"},"Pre-Install Checklist"),(0,r.kt)("ul",{className:"contains-task-list"},(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less"),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Clone the repository"),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Node.js 16 or 18 (earlier versions not guaranteed to work)"),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Python >=3.6 + ",(0,r.kt)("a",{parentName:"li",href:"https://pypi.org/project/pip/"},"PIP"),", C++, and\nother build tools. See the ",(0,r.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup install instructions"),"\nfor full details."),(0,r.kt)("li",{parentName:"ul",className:"task-list-item"},(0,r.kt)("input",{parentName:"li",type:"checkbox",checked:!1,disabled:!0})," ","Install Docker",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"(Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's ",(0,r.kt)("inlineCode",{parentName:"li"},".env.local")," accordingly.")))),(0,r.kt)("p",null,"You should now be ready to follow the ",(0,r.kt)("a",{parentName:"p",href:"#quick-start"},"Quick Start")," instructions."),(0,r.kt)("h3",{id:"clone-the-repository"},"Clone the repository"),(0,r.kt)("p",null,"A lot has changed during development, and our monorepo has gotten quite large.\nTo avoid cloning the entire thing, use this command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"git clone https://github.com/etherealengine/etherealengine --depth 1\n")),(0,r.kt)("h3",{id:"ensure-you-are-running-node-16-or-18"},"Ensure you are running Node 16 or 18"),(0,r.kt)("p",null,"The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions\nare not guaranteed to work properly."),(0,r.kt)("p",null,"A version manager can be helpful for this:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"NodeJS only: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/nvm-sh/nvm"},"NVM")),(0,r.kt)("li",{parentName:"ul"},"Polyglot: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/asdf-vm/asdf"},"ASDF"))),(0,r.kt)("p",null,"Before running the engine, please check ",(0,r.kt)("inlineCode",{parentName:"p"},"node --version"),"\nIf you are using a node version below 16, please update or nothing will work.\nYou will know you are having issues if you try to install at root and are\ngetting dependency errors."),(0,r.kt)("h3",{id:"docker-is-your-friend"},"Docker is your friend"),(0,r.kt)("p",null,"You don't need to use ",(0,r.kt)("a",{parentName:"p",href:"https://docs.docker.com/"},"Docker"),", but it will make\nyour life much easier.\nIf you don't wish to use Docker, you will need to setup mariadb and redis on\nyour machine. You can find credentials in ",(0,r.kt)("inlineCode",{parentName:"p"},"/scripts/docker-compose.yml")),(0,r.kt)("h2",{id:"quick-start"},"Quick Start"),(0,r.kt)("p",null,"If you are lucky, this will just work. However, you may encounter some\nissues. Make sure you are running Node 16, and check your dependencies."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cd path/to/etherealengine\ncp .env.local.default .env.local\nnpm install\nnpm run dev-docker\nnpm run dev-reinit\nnpm run dev\n")),(0,r.kt)("p",null,"Now run Ethereal Engine in browser by navigating to ",(0,r.kt)("a",{parentName:"p",href:"https://127.0.0.1:3000/location/default"},"this link"),". "),(0,r.kt)("h3",{id:"accept-certificates"},"Accept Certificates"),(0,r.kt)("p",null,"You'll have to tell your browser to ignore the insecure connections when you try to load the website."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates."),(0,r.kt)("li",{parentName:"ol"},"Open Developer tools in your browser by clicking the side menu with three dots, then ",(0,r.kt)("inlineCode",{parentName:"li"},"More tools > Developer tools")," (or use ",(0,r.kt)("inlineCode",{parentName:"li"},"Ctrl+Shift+I"),") and then go to the 'Console' tab."),(0,r.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab."),(0,r.kt)("li",{parentName:"ol"},"You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.")),(0,r.kt)("h3",{id:"admin-system-and-user-setup"},"Admin System and User Setup"),(0,r.kt)("p",null,"You can administrate many features from the admin panel at https://localhost:3000/admin"),(0,r.kt)("p",null,"To make a user an admin, open a page and open the profile menu. There is a button labelled ",(0,r.kt)("inlineCode",{parentName:"p"},"Show User ID"),"\nwhich opens a text field with your userId. Paste it in and run the following command in\nyour terminal:"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id={COPIED_USER_ID}")),(0,r.kt)("p",null,"Example:\n",(0,r.kt)("inlineCode",{parentName:"p"},"npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac")),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"image",src:n(2288).Z,width:"596",height:"294"})),(0,r.kt)("h4",{id:"alternate-method"},"Alternate Method:"),(0,r.kt)("p",null,"Look up in User table and change userRole to 'admin'\n(It helps to use a graphical database explorer, we recommend ",(0,r.kt)("a",{parentName:"p",href:"https://beekeeperstudio.io/"},"beekeeperstudio.io"),")"),(0,r.kt)("p",null,"Test user Admin privileges by going to ",(0,r.kt)("inlineCode",{parentName:"p"},"/admin")),(0,r.kt)("h2",{id:"advanced-installation-and-troubleshooting"},"Advanced Installation and Troubleshooting"),(0,r.kt)("p",null,"If you run into any trouble with the Quick Start instructions:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Please make sure you've followed the\n",(0,r.kt)("a",{parentName:"li",href:"https://mediasoup.org/documentation/v3/mediasoup/installation/"},"Mediasoup installation instructions")),(0,r.kt)("li",{parentName:"ul"},"Check your OS-specific instructions:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/windows"},"Installing on Windows (10+)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/mac_os_x"},"Installing on Mac OS X")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/install_troubleshooting"},"Installation Troubleshooting")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/etherealengine-docs/es/docs/host/installation/advanced_setup"},"Advanced Setup")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://vitejs.dev/guide/troubleshooting.html#dev-server"},"Vite dev server is stalling"))))}c.isMDXComponent=!0},2288:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/userid-6e9d6427255bba7ddcc06f3397a1567f.png"}}]); \ No newline at end of file diff --git a/es/assets/js/fc66d9af.fb62773e.js b/es/assets/js/fc66d9af.fb62773e.js new file mode 100644 index 000000000000..5339745995a3 --- /dev/null +++ b/es/assets/js/fc66d9af.fb62773e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[3113],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var a=r(7294);function n(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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},o=Object.keys(e);for(a=0;a<o.length;a++)r=o[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)r=o[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),c=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),h=c(r),u=n,m=h["".concat(l,".").concat(u)]||h[u]||d[u]||o;return r?a.createElement(m,i(i({ref:t},p),{},{components:r})):a.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=u;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,i[1]=s;for(var c=2;c<o;c++)i[c]=r[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,r)}u.displayName="MDXCreateElement"},1944:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=r(7462),n=(r(7294),r(3905));const o={id:"overview",title:"Overview",sidebar_label:"Overview",slug:"/",sidebar_position:0},i="Ethereal Engine",s={unversionedId:"overview",id:"overview",title:"Overview",description:"Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for",source:"@site/docs/0_start_here.md",sourceDirName:".",slug:"/",permalink:"/etherealengine-docs/es/docs/",draft:!1,editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/docs/0_start_here.md",tags:[],version:"current",sidebarPosition:0,frontMatter:{id:"overview",title:"Overview",sidebar_label:"Overview",slug:"/",sidebar_position:0},sidebar:"tutorialSidebar",next:{title:"Ethereal for Hosts",permalink:"/etherealengine-docs/es/docs/host/"}},l={},c=[{value:"WebXR Engine",id:"webxr-engine",level:2},{value:"On The Web",id:"on-the-web",level:2},{value:"Deployment Stack",id:"deployment-stack",level:2},{value:"Ethereal Studio",id:"ethereal-studio",level:2},{value:"Project API",id:"project-api",level:2},{value:"Stack Overview",id:"stack-overview",level:2}],p={toc:c},h="wrapper";function d(e){let{components:t,...o}=e;return(0,n.kt)(h,(0,a.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"ethereal-engine"},"Ethereal Engine"),(0,n.kt)("p",null,"Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for\nany reason - to host events, make games, showcase art, or just to provide a space for your community. There are plenty of platforms on which you can spend a bit to have a world, but you can't be in complete control of the experience or customise it from the ground up."),(0,n.kt)("p",null,"When the Ethereal Engine stack is deployed, that stack is sovereign, open and cross\nplatform by default. Users can create any kind of game or experience with no limits.\nWith the tech that's being built now, users will be able to seamlessly travel\nthrough portals from any worlds to any other world, on different servers, and have all\ntheir data and identity travel with them."),(0,n.kt)("p",null,"This technology is for everyone, but especially people who want to build or\nbelong to a community."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(1769).Z,width:"1600",height:"900"})),(0,n.kt)("h2",{id:"webxr-engine"},"WebXR Engine"),(0,n.kt)("p",null,"The core engine is the heart of Ethereal Engine. Based around the WebXR spec, brought to life with libraries such as ",(0,n.kt)("a",{parentName:"p",href:"https://threejs.org/"},"threejs"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/NateTheGreatt/bitECS"},"bitecs"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/dimforge/rapier.js"},"rapier.js"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/versatica/mediasoup"},"Mediasoup WebRTC"),", ",(0,n.kt)("a",{parentName:"p",href:"https://reactjs.org/"},"reactjs")," & ",(0,n.kt)("a",{parentName:"p",href:"https://hookstate.js.org/"},"hookstatejs"),". With the latest understanding of Data-Oriented Design, ECS and Event-Sourcing paradigms, we have put together a robust MMO XR framework that rivals AAA capabilities, quality and speed."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(9737).Z,width:"3402",height:"1695"})),(0,n.kt)("h2",{id:"on-the-web"},"On The Web"),(0,n.kt)("p",null,"Built for the web, Ethereal Engine providers a fully customisable and clean UI that works in both immersive and non-immersive contexts, as well as an administration panel for full control of deployment, locations, projects, avatars, custom routes & more."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(7204).Z,width:"1586",height:"884"})),(0,n.kt)("h2",{id:"deployment-stack"},"Deployment Stack"),(0,n.kt)("p",null,"Running on the backend is a state of the art fullstack framework, template & deployment pipeline using ",(0,n.kt)("a",{parentName:"p",href:"https://kubernetes.io/"},"kubernetes"),", ",(0,n.kt)("a",{parentName:"p",href:"https://www.docker.com/"},"docker"),", ",(0,n.kt)("a",{parentName:"p",href:"https://agones.dev/site/"},"agones"),", ",(0,n.kt)("a",{parentName:"p",href:"https://open-match.dev/site/"},"openmatch")," & ",(0,n.kt)("a",{parentName:"p",href:"https://feathersjs.com/"},"feathersjs"),". The result is a fully customisable and scalable web app."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(9468).Z,width:"1068",height:"731"})),(0,n.kt)("h2",{id:"ethereal-studio"},"Ethereal Studio"),(0,n.kt)("p",null,"The Studio sits on top of the engine, as a heavily modified version of ",(0,n.kt)("a",{parentName:"p",href:"https://hubs.mozilla.com/spoke"},"Mozilla Hubs' Spoke editor"),". It has been transformed with the engine and the web app to provide a fast and comprehensive Content Management System, file browser, cloud edge caching, content pipeline tools and other creator tools."),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(6711).Z,width:"1080",height:"608"})),(0,n.kt)("h2",{id:"project-api"},"Project API"),(0,n.kt)("p",null,"The Project API is the core of what makes Ethereal Engine shine - the ability to load your own scenes, assets & code with a click of a button. Using github, we allow users to have fully version controlled access to extend the base functionality. You can see examples of the Project API in action ",(0,n.kt)("a",{parentName:"p",href:"https://etherealengine.com/explore"},"here")," and ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/EtherealEngine/ee-development-test-suite"},"here")),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(745).Z,width:"789",height:"404"})),(0,n.kt)("h2",{id:"stack-overview"},"Stack Overview"),(0,n.kt)("p",null,(0,n.kt)("img",{src:r(4724).Z,width:"653",height:"977"})))}d.isMDXComponent=!0},7204:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/admin-panel-81755b9d896cb7c7e6858214ce92eab2.jpg"},9468:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/backend-k8s-534df686ec034f005501a65cfc7774ca.jpg"},1769:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/ethereal-engine-8d911493ecb7e7aac1e1a4daa2f24cd2.jpg"},745:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/project-api-e80263cc00439de971d2d72094af6de9.jpg"},6711:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/puttclub-editor-e4fc896c8666e2b99b58aa3ba80ea0e4.jpg"},4724:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/stack-bb67f2fb51f06fc477088a4b481f6ab9.png"},9737:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/treehouse-5575f0864bc4630ce0f7ff972d2cd69a.jpeg"}}]); \ No newline at end of file diff --git a/es/assets/js/main.687acc7d.js b/es/assets/js/main.687acc7d.js new file mode 100644 index 000000000000..163e3f3301f5 --- /dev/null +++ b/es/assets/js/main.687acc7d.js @@ -0,0 +1,2 @@ +/*! For license information please see main.687acc7d.js.LICENSE.txt */ +(self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[]).push([[179],{830:(e,t,n)=>{"use strict";n.d(t,{W:()=>a});var r=n(7294);function a(){return r.createElement("svg",{width:"20",height:"20",className:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},r.createElement("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}},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={"0304d7f4":[()=>n.e(8953).then(n.bind(n,8359)),"@site/docs/2_creator/4_development/3_networking.md",8359],"0346e14a":[()=>n.e(720).then(n.bind(n,7887)),"@site/docs/1_host/2_devops_deployment/2_installing_projects.md",7887],"06bf4b13":[()=>n.e(5572).then(n.bind(n,8050)),"@site/docs/1_host/1_installation/8_opensearch.md",8050],"0991b023":[()=>n.e(6524).then(n.bind(n,8778)),"@site/docs/2_creator/1_concepts/readme.md",8778],"0f5dde8f":[()=>n.e(3976).then(n.bind(n,1868)),"@site/docs/1_host/3_Admin_Dashboard/readme.md",1868],"12905b1d":[()=>n.e(2345).then(n.bind(n,3686)),"@site/docs/1_host/2_devops_deployment/4_setup_github_oauth_for_projects.md",3686],"14d2cd64":[()=>n.e(2901).then(n.bind(n,3219)),"@site/docs/2_creator/4_development/1_state_management.md",3219],"15dae980":[()=>n.e(1489).then(n.bind(n,8453)),"@site/docs/1_host/1_installation/3_windows_wsl.md",8453],17896441:[()=>Promise.all([n.e(3312),n.e(272),n.e(7918)]).then(n.bind(n,903)),"@theme/DocItem",903],"1a4e3797":[()=>Promise.all([n.e(3312),n.e(7920)]).then(n.bind(n,6675)),"@theme/SearchPage",6675],"1be78505":[()=>Promise.all([n.e(3312),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1df93b7f":[()=>Promise.all([n.e(3312),n.e(3237)]).then(n.bind(n,3808)),"@site/src/pages/index.tsx",3808],"1f391b9e":[()=>Promise.all([n.e(3312),n.e(272),n.e(3085)]).then(n.bind(n,4247)),"@theme/MDXPage",4247],"222ee964":[()=>n.e(401).then(n.t.bind(n,3769,19)),"/home/runner/work/etherealengine/etherealengine/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],24869598:[()=>n.e(3573).then(n.bind(n,8170)),"@site/docs/1_host/2_devops_deployment/6_release_helm_chart.md",8170],"271238cb":[()=>n.e(5003).then(n.bind(n,1468)),"@site/docs/2_creator/6_testing/5_debugging_device_wsl.md",1468],"28d03809":[()=>n.e(1423).then(n.bind(n,3030)),"@site/docs/2_creator/2_studio/readme.md",3030],"291a898d":[()=>n.e(2606).then(n.bind(n,9871)),"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/readme.md",9871],"33e7527e":[()=>n.e(2984).then(n.t.bind(n,7085,19)),"/home/runner/work/etherealengine/etherealengine/docs/.docusaurus/docusaurus-theme-search-algolia/default/plugin-route-context-module-100.json",7085],"393be207":[()=>n.e(7414).then(n.bind(n,3123)),"@site/src/pages/markdown-page.md",3123],"3c3cda30":[()=>n.e(9037).then(n.bind(n,7360)),"@site/docs/1_host/2_devops_deployment/0_microk8s_windows.md",7360],"3ec03ade":[()=>n.e(6916).then(n.bind(n,5545)),"@site/docs/1_host/1_installation/5_running_on_static_IP.md",5545],"46dcad74":[()=>n.e(5520).then(n.bind(n,6506)),"@site/docs/1_host/1_installation/6_install_troubleshooting.md",6506],47408852:[()=>n.e(2130).then(n.bind(n,496)),"@site/docs/2_creator/6_testing/readme.md",496],"4a109b8c":[()=>n.e(943).then(n.bind(n,8960)),"@site/docs/2_creator/4_development/0_projects_overview.md",8960],"4a62c6ed":[()=>n.e(5624).then(n.bind(n,8510)),"@site/docs/2_creator/4_development/readme.md",8510],"4b422948":[()=>n.e(3881).then(n.bind(n,3825)),"@site/docs/1_host/2_devops_deployment/8_tutorials/1_ethereal_control_center/01_getting_started.md",3825],"4c80fdcb":[()=>n.e(8511).then(n.bind(n,4155)),"@site/docs/2_creator/5_tutorials/1_ethereal_engine/readme.md",4155],"530a89a7":[()=>n.e(5111).then(n.bind(n,1869)),"@site/docs/2_creator/5_tutorials/1_ethereal_engine/01_unity_bridge.md",1869],"54e37525":[()=>n.e(6718).then(n.bind(n,5888)),"@site/docs/2_creator/6_testing/2_reasonable_code.md",5888],58222842:[()=>n.e(8718).then(n.bind(n,765)),"@site/docs/1_host/2_devops_deployment/2_AWS_setup.md",765],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"6807199d":[()=>n.e(301).then(n.bind(n,6364)),"@site/docs/2_creator/7_avatars/readme.md",6364],75750052:[()=>n.e(532).then(n.bind(n,2510)),"@site/docs/2_creator/6_testing/4_debugging.md",2510],"82399a21":[()=>n.e(1473).then(n.bind(n,8993)),"@site/docs/2_creator/5_tutorials/1_ethereal_engine/02_unreal_bridge.md",8993],"86c50ec3":[()=>n.e(8625).then(n.bind(n,183)),"@site/docs/1_host/1_installation/2_mac_os_x.md",183],"8df89772":[()=>n.e(8620).then(n.bind(n,4085)),"@site/docs/2_creator/3_importing_assets/readme.md",4085],"917fb754":[()=>n.e(7053).then(n.bind(n,2018)),"@site/docs/2_creator/5_tutorials/readme.md",2018],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"95bfc3a6":[()=>n.e(5459).then(n.bind(n,9702)),"@site/docs/1_host/2_devops_deployment/8_tutorials/readme.md",9702],"9a2a3fee":[()=>n.e(5229).then(n.bind(n,3901)),"@site/docs/1_host/2_devops_deployment/3_database_migrations.md",3901],a1c60d7a:[()=>n.e(8949).then(n.bind(n,1144)),"@site/docs/3_guest/readme.md",1144],a47a1e93:[()=>n.e(5992).then(n.bind(n,7878)),"@site/docs/2_creator/6_testing/1_testing_intro.md",7878],a91c512d:[()=>n.e(4449).then(n.bind(n,6793)),"@site/docs/1_host/2_devops_deployment/1_docker_desktop.md",6793],b04e8f41:[()=>n.e(2142).then(n.bind(n,1173)),"@site/docs/2_creator/1_concepts/1_editor_scenes_locations.md",1173],b5eb9e9a:[()=>n.e(6658).then(n.bind(n,7157)),"@site/docs/1_host/1_installation/3_windows.md",7157],b68e3f8b:[()=>n.e(543).then(n.bind(n,450)),"@site/docs/1_host/2_devops_deployment/readme.md",450],bddbf10d:[()=>n.e(8823).then(n.bind(n,2401)),"@site/docs/1_host/readme.md",2401],c538f40f:[()=>n.e(3850).then(n.bind(n,8580)),"@site/docs/2_creator/readme.md",8580],c7af7f81:[()=>n.e(4380).then(n.bind(n,6030)),"@site/docs/1_host/2_devops_deployment/0_microk8s_linux.md",6030],cc938c89:[()=>n.e(3709).then(n.bind(n,4458)),"@site/docs/2_creator/6_testing/3_test_driven_development.md",4458],cf339e2e:[()=>n.e(4438).then(n.t.bind(n,5745,19)),"/home/runner/work/etherealengine/etherealengine/docs/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],d05402c5:[()=>n.e(6970).then(n.bind(n,6064)),"@site/docs/2_creator/4_development/4_actions_event_sourcing.md",6064],d43455fa:[()=>n.e(1205).then(n.bind(n,9347)),"@site/docs/2_creator/4_development/2_ecs.md",9347],d50cf8bd:[()=>n.e(1364).then(n.bind(n,9466)),"@site/docs/2_creator/6_testing/6_debugging_deployed_instanceservers.md",9466],d519f5a1:[()=>n.e(5046).then(n.bind(n,806)),"@site/docs/2_creator/4_development/5_behave_graph.md",806],d7cf77e2:[()=>n.e(314).then(n.bind(n,7046)),"@site/docs/1_host/1_installation/4_advanced_setup.md",7046],d88112b6:[()=>n.e(176).then(n.bind(n,6792)),"@site/docs/1_host/2_devops_deployment/5_managing_remote_kubernetes.md",6792],dcc1f912:[()=>n.e(3666).then(n.bind(n,1100)),"@site/docs/1_host/2_devops_deployment/7_upgrade_helm_deployment.md",1100],e988a1b0:[()=>n.e(4705).then(n.bind(n,9128)),"@site/docs/1_host/1_installation/7_docker.md",9128],ea08158a:[()=>n.e(4995).then(n.bind(n,4501)),"@site/docs/1_host/2_devops_deployment/1_minikube.md",4501],ebc45004:[()=>n.e(5194).then(n.bind(n,8192)),"@site/docs/1_host/1_installation/1_basic_setup.md",8192],f7429bc1:[()=>n.e(3179).then(n.bind(n,932)),"@site/docs/1_host/1_installation/readme.md",932],fc66d9af:[()=>n.e(3113).then(n.bind(n,1944)),"@site/docs/0_start_here.md",1944]};function c(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 u=n(9670),d=n(226);function p(e,t){if("*"===e)return i()({loading:c,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=[],h=(0,u.Z)(o);return Object.entries(h).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:c,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:"/etherealengine-docs/es/markdown-page",component:p("/etherealengine-docs/es/markdown-page","de3"),exact:!0},{path:"/etherealengine-docs/es/search",component:p("/etherealengine-docs/es/search","dc5"),exact:!0},{path:"/etherealengine-docs/es/docs",component:p("/etherealengine-docs/es/docs","f5e"),routes:[{path:"/etherealengine-docs/es/docs/",component:p("/etherealengine-docs/es/docs/","d34"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/",component:p("/etherealengine-docs/es/docs/creator/","c2b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/avatars/",component:p("/etherealengine-docs/es/docs/creator/avatars/","7cf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/concepts/",component:p("/etherealengine-docs/es/docs/creator/concepts/","bcd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations",component:p("/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations","d8e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/",component:p("/etherealengine-docs/es/docs/creator/development/","487"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing",component:p("/etherealengine-docs/es/docs/creator/development/actions_event_sourcing","c7c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/behave_graph",component:p("/etherealengine-docs/es/docs/creator/development/behave_graph","fef"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/ecs",component:p("/etherealengine-docs/es/docs/creator/development/ecs","5ba"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/networking",component:p("/etherealengine-docs/es/docs/creator/development/networking","7e9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/projects_overview",component:p("/etherealengine-docs/es/docs/creator/development/projects_overview","8a3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/development/state_management",component:p("/etherealengine-docs/es/docs/creator/development/state_management","f5d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/importing_assets/",component:p("/etherealengine-docs/es/docs/creator/importing_assets/","287"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/studio/",component:p("/etherealengine-docs/es/docs/creator/studio/","903"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/",component:p("/etherealengine-docs/es/docs/creator/testing/","005"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/debugging",component:p("/etherealengine-docs/es/docs/creator/testing/debugging","d27"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers",component:p("/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers","17d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl",component:p("/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl","963"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/reasonable_code",component:p("/etherealengine-docs/es/docs/creator/testing/reasonable_code","a47"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/test_driven_development",component:p("/etherealengine-docs/es/docs/creator/testing/test_driven_development","dfe"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/testing/testing_intro",component:p("/etherealengine-docs/es/docs/creator/testing/testing_intro","61d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/tutorials/",component:p("/etherealengine-docs/es/docs/creator/tutorials/","30e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/",component:p("/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/","43e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge",component:p("/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge","5ee"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge",component:p("/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge","958"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/guest/",component:p("/etherealengine-docs/es/docs/guest/","d4a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/",component:p("/etherealengine-docs/es/docs/host/","a22"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/Admin_Dashboard/",component:p("/etherealengine-docs/es/docs/host/Admin_Dashboard/","352"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/",component:p("/etherealengine-docs/es/docs/host/devops_deployment/","ecb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup",component:p("/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup","4c0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations",component:p("/etherealengine-docs/es/docs/host/devops_deployment/database_migrations","90e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop",component:p("/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop","090"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects",component:p("/etherealengine-docs/es/docs/host/devops_deployment/installing_projects","b67"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes",component:p("/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes","f6b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux",component:p("/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux","35b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows",component:p("/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows","ce3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/minikube",component:p("/etherealengine-docs/es/docs/host/devops_deployment/minikube","134"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart",component:p("/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart","33b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects",component:p("/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects","8af"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/",component:p("/etherealengine-docs/es/docs/host/devops_deployment/tutorials/","0ab"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/",component:p("/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/","d30"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started",component:p("/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started","ffc"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment",component:p("/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment","52d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/",component:p("/etherealengine-docs/es/docs/host/installation/","246"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/advanced_setup",component:p("/etherealengine-docs/es/docs/host/installation/advanced_setup","913"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/basic_setup",component:p("/etherealengine-docs/es/docs/host/installation/basic_setup","f4f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/docker",component:p("/etherealengine-docs/es/docs/host/installation/docker","06a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/install_troubleshooting",component:p("/etherealengine-docs/es/docs/host/installation/install_troubleshooting","17d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/mac_os_x",component:p("/etherealengine-docs/es/docs/host/installation/mac_os_x","e5c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/opensearch",component:p("/etherealengine-docs/es/docs/host/installation/opensearch","426"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/running_on_static_IP",component:p("/etherealengine-docs/es/docs/host/installation/running_on_static_IP","af7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/windows",component:p("/etherealengine-docs/es/docs/host/installation/windows","8f7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/etherealengine-docs/es/docs/host/installation/windows_wsl",component:p("/etherealengine-docs/es/docs/host/installation/windows_wsl","e6b"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/etherealengine-docs/es/",component:p("/etherealengine-docs/es/","cfa"),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 c=n(723),u=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),h=n(2263),g=n(4996),b=n(6668),v=n(833),y=n(4711),w=n(9727),k=n(3320),_=n(197);function S(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,h.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 E(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,h.Z)(),a=function(){const{siteConfig:{url:e}}=(0,h.Z)(),{pathname:t}=(0,u.TH)();return e+(0,g.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 x(){const{i18n:{currentLocale:e}}=(0,h.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(E,null),r.createElement(S,null),r.createElement(_.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 T=new Map;function C(e){if(T.has(e.pathname))return{...e,pathname:T.get(e.pathname)};if((0,d.f)(c.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return T.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return T.set(e.pathname,t),{...e,pathname:t}}var A=n(8934),L=n(8940);function R(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=s.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const P=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),R("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)(c.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?R("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=R("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(P,{previousLocation:this.previousLocation,location:t},r.createElement(u.AW,{location:t,render:()=>e}))}}const I=O,D="docusaurus-base-url-issue-banner-container",M="docusaurus-base-url-issue-banner",B="docusaurus-base-url-issue-banner-suggestion-container",F="__DOCUSAURUS_INSERT_BASEURL_BANNER";function j(e){return`\nwindow['${F}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${F}'];\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<div id="${M}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${B}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${B}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function U(){const{siteConfig:{baseUrl:e}}=(0,h.Z)();return(0,r.useLayoutEffect)((()=>{window[F]=!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 z(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,h.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?r.createElement(U,null):null}function $(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:o}}=(0,h.Z)(),i=(0,g.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 H(){const e=(0,d.H)(c.Z),t=(0,u.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(x,null),r.createElement(z,null),r.createElement(I,{location:C(t)},e)))))}var G=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,K=new Set,Y=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Q={prefetch(e){if(!(e=>!Y()&&!K.has(e)&&!W.has(e))(e))return!1;W.add(e);const t=(0,d.f)(c.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(G).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,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=>!Y()&&!K.has(e))(e)&&(K.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(H,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/etherealengine-docs/es/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/etherealengine-docs/es/docs","mainDocId":"overview","docs":[{"id":"creator/avatars/readme","path":"/etherealengine-docs/es/docs/creator/avatars/","sidebar":"tutorialSidebar"},{"id":"creator/concepts/editor_scenes_locations","path":"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations","sidebar":"tutorialSidebar"},{"id":"creator/concepts/readme","path":"/etherealengine-docs/es/docs/creator/concepts/","sidebar":"tutorialSidebar"},{"id":"creator/development/actions_event_sourcing","path":"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing","sidebar":"tutorialSidebar"},{"id":"creator/development/behave_graph","path":"/etherealengine-docs/es/docs/creator/development/behave_graph","sidebar":"tutorialSidebar"},{"id":"creator/development/ecs","path":"/etherealengine-docs/es/docs/creator/development/ecs","sidebar":"tutorialSidebar"},{"id":"creator/development/networking","path":"/etherealengine-docs/es/docs/creator/development/networking","sidebar":"tutorialSidebar"},{"id":"creator/development/projects_overview","path":"/etherealengine-docs/es/docs/creator/development/projects_overview","sidebar":"tutorialSidebar"},{"id":"creator/development/readme","path":"/etherealengine-docs/es/docs/creator/development/","sidebar":"tutorialSidebar"},{"id":"creator/development/state_management","path":"/etherealengine-docs/es/docs/creator/development/state_management","sidebar":"tutorialSidebar"},{"id":"creator/importing_assets/readme","path":"/etherealengine-docs/es/docs/creator/importing_assets/","sidebar":"tutorialSidebar"},{"id":"creator/readme","path":"/etherealengine-docs/es/docs/creator/","sidebar":"tutorialSidebar"},{"id":"creator/studio/readme","path":"/etherealengine-docs/es/docs/creator/studio/","sidebar":"tutorialSidebar"},{"id":"creator/testing/debugging","path":"/etherealengine-docs/es/docs/creator/testing/debugging","sidebar":"tutorialSidebar"},{"id":"creator/testing/debugging_deployed_instanceservers","path":"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers","sidebar":"tutorialSidebar"},{"id":"creator/testing/debugging_device_wsl","path":"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl","sidebar":"tutorialSidebar"},{"id":"creator/testing/readme","path":"/etherealengine-docs/es/docs/creator/testing/","sidebar":"tutorialSidebar"},{"id":"creator/testing/reasonable_code","path":"/etherealengine-docs/es/docs/creator/testing/reasonable_code","sidebar":"tutorialSidebar"},{"id":"creator/testing/test_driven_development","path":"/etherealengine-docs/es/docs/creator/testing/test_driven_development","sidebar":"tutorialSidebar"},{"id":"creator/testing/testing_intro","path":"/etherealengine-docs/es/docs/creator/testing/testing_intro","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/ethereal_engine/readme","path":"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/ethereal_engine/unity_bridge","path":"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/ethereal_engine/unreal_bridge","path":"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge","sidebar":"tutorialSidebar"},{"id":"creator/tutorials/readme","path":"/etherealengine-docs/es/docs/creator/tutorials/","sidebar":"tutorialSidebar"},{"id":"guest/readme","path":"/etherealengine-docs/es/docs/guest/","sidebar":"tutorialSidebar"},{"id":"host/Admin_Dashboard/readme","path":"/etherealengine-docs/es/docs/host/Admin_Dashboard/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/AWS_setup","path":"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/database_migrations","path":"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/docker_desktop","path":"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/installing_projects","path":"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/managing_remote_kubernetes","path":"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/microk8s_linux","path":"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/microk8s_windows","path":"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/minikube","path":"/etherealengine-docs/es/docs/host/devops_deployment/minikube","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/readme","path":"/etherealengine-docs/es/docs/host/devops_deployment/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/release_helm_chart","path":"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/setup_github_oauth_for_projects","path":"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/tutorials/ethereal_control_center/getting_started","path":"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/tutorials/ethereal_control_center/readme","path":"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/tutorials/readme","path":"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/","sidebar":"tutorialSidebar"},{"id":"host/devops_deployment/upgrade_helm_deployment","path":"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment","sidebar":"tutorialSidebar"},{"id":"host/installation/advanced_setup","path":"/etherealengine-docs/es/docs/host/installation/advanced_setup","sidebar":"tutorialSidebar"},{"id":"host/installation/basic_setup","path":"/etherealengine-docs/es/docs/host/installation/basic_setup","sidebar":"tutorialSidebar"},{"id":"host/installation/docker","path":"/etherealengine-docs/es/docs/host/installation/docker","sidebar":"tutorialSidebar"},{"id":"host/installation/install_troubleshooting","path":"/etherealengine-docs/es/docs/host/installation/install_troubleshooting","sidebar":"tutorialSidebar"},{"id":"host/installation/mac_os_x","path":"/etherealengine-docs/es/docs/host/installation/mac_os_x","sidebar":"tutorialSidebar"},{"id":"host/installation/opensearch","path":"/etherealengine-docs/es/docs/host/installation/opensearch","sidebar":"tutorialSidebar"},{"id":"host/installation/readme","path":"/etherealengine-docs/es/docs/host/installation/","sidebar":"tutorialSidebar"},{"id":"host/installation/running_on_static_IP","path":"/etherealengine-docs/es/docs/host/installation/running_on_static_IP","sidebar":"tutorialSidebar"},{"id":"host/installation/windows","path":"/etherealengine-docs/es/docs/host/installation/windows","sidebar":"tutorialSidebar"},{"id":"host/installation/windows_wsl","path":"/etherealengine-docs/es/docs/host/installation/windows_wsl","sidebar":"tutorialSidebar"},{"id":"host/readme","path":"/etherealengine-docs/es/docs/host/","sidebar":"tutorialSidebar"},{"id":"overview","path":"/etherealengine-docs/es/docs/","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/etherealengine-docs/es/docs/","label":"Overview"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en","es"],"path":"i18n","currentLocale":"es","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"},"es":{"label":"Espa\xf1ol","direction":"ltr","htmlLang":"es","calendar":"gregory","path":"es"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.4.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.4.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.4.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.0"},"docusaurus-theme-search-algolia":{"type":"package","name":"@docusaurus/theme-search-algolia","version":"2.4.0"}}}'),c={siteConfig:a.default,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},u=r.createContext(c);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:c},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(412),o=n(5742),i=n(8780),l=n(7452);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},r.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),r.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),r.createElement(c,{error:t}))}function c(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function u(e){let{error:t,tryAgain:n}=e;return r.createElement(p,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(o.Z,null,r.createElement("title",null,"Page Error")),r.createElement(l.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const d=e=>r.createElement(u,e);class p 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??d)(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),c=n(412);const u=a.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:h,"data-noBrokenLinkCheck":g,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.Z)(),{withBaseUrl:k}=(0,d.C)(),_=(0,a.useContext)(u),S=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>S.current));const E=p||f;const x=(0,s.Z)(E),T=E?.replace("pathname://","");let C=void 0!==T?(A=T,b&&(e=>e.startsWith("/"))(A)?k(A):A):void 0;var A;C&&x&&(C=(0,i.applyTrailingSlash)(C,{trailingSlash:y,baseUrl:w}));const L=(0,a.useRef)(!1),R=n?o.OL:o.rU,P=c.Z.canUseIntersectionObserver,N=(0,a.useRef)(),O=()=>{L.current||null==C||(window.docusaurus.preload(C),L.current=!0)};(0,a.useEffect)((()=>(!P&&x&&null!=C&&window.docusaurus.prefetch(C),()=>{P&&N.current&&N.current.disconnect()})),[N,C,P,x]);const I=C?.startsWith("#")??!1,D=!C||!x||I;return D||g||_.collectLink(C),D?a.createElement("a",(0,r.Z)({ref:S,href:C},E&&!x&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(R,(0,r.Z)({},v,{onMouseEnter:O,onTouchStart:O,innerRef:e=>{S.current=e,P&&e&&x&&(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!=C&&window.docusaurus.prefetch(C))}))})),N.current.observe(e))},to:C},n&&{isActive:h,activeClassName:m}))}const f=a.forwardRef(p)},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 <Translate> children",t),new Error("The Docusaurus <Translate> 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:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();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:()=>b,gA:()=>f,WS:()=>m,_r:()=>d,Jo:()=>v,zh:()=>p,yW:()=>g,gB:()=>h});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=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}function c(e,t){const n=s(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={},d=()=>i("docusaurus-plugin-content-docs")??u,p=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 f(e){void 0===e&&(e={});const t=d(),{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 m(e){void 0===e&&(e={});const t=f(e),{pathname:n}=(0,r.TH)();if(!t)return;return{activePlugin:t,activeVersion:s(t.pluginData,n)}}function h(e){return p(e).versions}function g(e){const t=p(e);return l(t)}function b(e){const t=p(e),{pathname:n}=(0,r.TH)();return c(t,n)}function v(e){const t=p(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:c(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"}))}},7452:(e,t,n)=>{"use strict";n.d(t,{Z:()=>Rt});var r=n(7294),a=n(6010),o=n(4763),i=n(833),l=n(7462),s=n(6550),c=n(5999),u=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,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.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 h(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 g=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(h,{className:v.skipToContent})}var w=n(6668),k=n(9689);function _(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 E(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,c.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(_,{width:14,height:14,strokeWidth:3.1}))}const x={content:"content_knG7"};function T(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(x.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const C={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:C.announcementBar,style:{backgroundColor:a,color:o},role:"banner"},i&&r.createElement("div",{className:C.announcementBarPlaceholder}),r.createElement(T,{className:C.announcementBarContent}),i&&r.createElement(E,{onClick:n,className:C.announcementBarClose}))}var L=n(3163),R=n(2466);var P=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,P.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 P.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 B(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 F=n(2949),j=n(2389);function U(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function z(e){return r.createElement("svg",(0,l.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 $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function q(e){let{className:t,buttonClassName:n,value:o,onChange:i}=e;const l=(0,j.Z)(),s=(0,c.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"===o?(0,c.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)($.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",$.toggleButton,!l&&$.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===o?"light":"dark"),disabled:!l,title:s,"aria-label":s,"aria-live":"polite"},r.createElement(U,{className:(0,a.Z)($.toggleIcon,$.lightToggleIcon)}),r.createElement(z,{className:(0,a.Z)($.toggleIcon,$.darkToggleIcon)})))}const H=r.memo(q),G={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function Z(e){let{className:t}=e;const n=(0,w.L)().navbar.style,a=(0,w.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:i}=(0,F.I)();return a?null:r.createElement(H,{className:t,buttonClassName:"dark"===n?G.darkNavbarColorModeToggle:void 0,value:o,onChange:i})}var V=n(1327);function W(){return r.createElement(V.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,L.e)();return r.createElement("button",{type:"button","aria-label":(0,c.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(_,{color:"var(--ifm-color-emphasis-600)"}))}function Y(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(W,null),r.createElement(Z,{className:"margin-right--md"}),r.createElement(K,null))}var Q=n(9960),X=n(4996),J=n(3919),ee=n(8022),te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const p=(0,X.Z)(a),f=(0,X.Z)(t),m=(0,X.Z)(o,{forcePrependBaseUrl:!0}),h=i&&o&&!(0,J.Z)(o),g=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,h&&r.createElement(te.Z,c&&{width:12,height:12}))};return o?r.createElement(Q.Z,(0,l.Z)({href:u?m:o},d,g)):r.createElement(Q.Z,(0,l.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?(0,ee.F)(n,t.pathname):t.pathname.startsWith(f)},d,g))}function re(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(ne,(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 ae(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ne,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function oe(e){let{mobile:t=!1,position:n,...a}=e;const o=t?ae:re;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(6043),le=n(8596),se=n(2263);function ce(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!(0,ee.F)(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:o,onClick:i,...s}=e;const c=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[c]),r.createElement("div",{ref:c,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(ne,(0,l.Z)({"aria-haspopup":"true","aria-expanded":u,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(!u))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>r.createElement(qe,(0,l.Z)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:o,onClick:i,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,se.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=ce(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(ne,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),f()}}),c.children??c.label),r.createElement(ie.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(qe,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function pe(e){let{mobile:t=!1,...n}=e;const a=t?de:ue;return r.createElement(a,n)}var fe=n(4711);function me(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 he="iconLanguage_nlXk";function ge(){return r.createElement("svg",{width:"15",height:"15",className:"DocSearch-Control-Key-Icon"},r.createElement("path",{d:"M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953",strokeWidth:"1.2",stroke:"currentColor",fill:"none",strokeLinecap:"square"}))}var be=n(830),ve=["translations"];function ye(){return ye=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},ye.apply(this,arguments)}function we(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,a,o=[],i=!0,l=!1;try{for(n=n.call(e);!(i=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);i=!0);}catch(s){l=!0,a=s}finally{try{i||null==n.return||n.return()}finally{if(l)throw a}}return o}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return ke(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ke(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ke(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function _e(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var Se="Ctrl";var Ee=r.forwardRef((function(e,t){var n=e.translations,a=void 0===n?{}:n,o=_e(e,ve),i=a.buttonText,l=void 0===i?"Search":i,s=a.buttonAriaLabel,c=void 0===s?"Search":s,u=we((0,r.useState)(null),2),d=u[0],p=u[1];return(0,r.useEffect)((function(){"undefined"!=typeof navigator&&(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?p("\u2318"):p(Se))}),[]),r.createElement("button",ye({type:"button",className:"DocSearch DocSearch-Button","aria-label":c},o,{ref:t}),r.createElement("span",{className:"DocSearch-Button-Container"},r.createElement(be.W,null),r.createElement("span",{className:"DocSearch-Button-Placeholder"},l)),r.createElement("span",{className:"DocSearch-Button-Keys"},null!==d&&r.createElement(r.Fragment,null,r.createElement("kbd",{className:"DocSearch-Button-Key"},d===Se?r.createElement(ge,null):d),r.createElement("kbd",{className:"DocSearch-Button-Key"},"K"))))})),xe=n(5742),Te=n(6177),Ce=n(239),Ae=n(3320);var Le=n(3935);const Re={button:{buttonText:(0,c.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"}),buttonAriaLabel:(0,c.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"})},modal:{searchBox:{resetButtonTitle:(0,c.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),resetButtonAriaLabel:(0,c.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),cancelButtonText:(0,c.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"}),cancelButtonAriaLabel:(0,c.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"})},startScreen:{recentSearchesTitle:(0,c.I)({id:"theme.SearchModal.startScreen.recentSearchesTitle",message:"Recent",description:"The title for recent searches"}),noRecentSearchesText:(0,c.I)({id:"theme.SearchModal.startScreen.noRecentSearchesText",message:"No recent searches",description:"The text when no recent searches"}),saveRecentSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.saveRecentSearchButtonTitle",message:"Save this search",description:"The label for save recent search button"}),removeRecentSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.removeRecentSearchButtonTitle",message:"Remove this search from history",description:"The label for remove recent search button"}),favoriteSearchesTitle:(0,c.I)({id:"theme.SearchModal.startScreen.favoriteSearchesTitle",message:"Favorite",description:"The title for favorite searches"}),removeFavoriteSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle",message:"Remove this search from favorites",description:"The label for remove favorite search button"})},errorScreen:{titleText:(0,c.I)({id:"theme.SearchModal.errorScreen.titleText",message:"Unable to fetch results",description:"The title for error screen of search modal"}),helpText:(0,c.I)({id:"theme.SearchModal.errorScreen.helpText",message:"You might want to check your network connection.",description:"The help text for error screen of search modal"})},footer:{selectText:(0,c.I)({id:"theme.SearchModal.footer.selectText",message:"to select",description:"The explanatory text of the action for the enter key"}),selectKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.selectKeyAriaLabel",message:"Enter key",description:"The ARIA label for the Enter key button that makes the selection"}),navigateText:(0,c.I)({id:"theme.SearchModal.footer.navigateText",message:"to navigate",description:"The explanatory text of the action for the Arrow up and Arrow down key"}),navigateUpKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.navigateUpKeyAriaLabel",message:"Arrow up",description:"The ARIA label for the Arrow up key button that makes the navigation"}),navigateDownKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.navigateDownKeyAriaLabel",message:"Arrow down",description:"The ARIA label for the Arrow down key button that makes the navigation"}),closeText:(0,c.I)({id:"theme.SearchModal.footer.closeText",message:"to close",description:"The explanatory text of the action for Escape key"}),closeKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.closeKeyAriaLabel",message:"Escape key",description:"The ARIA label for the Escape key button that close the modal"}),searchByText:(0,c.I)({id:"theme.SearchModal.footer.searchByText",message:"Search by",description:"The text explain that the search is making by Algolia"})},noResultsScreen:{noResultsText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.noResultsText",message:"No results for",description:"The text explains that there are no results for the following search"}),suggestedQueryText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.suggestedQueryText",message:"Try searching for",description:"The text for the suggested query when no results are found for the following search"}),reportMissingResultsText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsText",message:"Believe this query should return results?",description:"The text for the question where the user thinks there are missing results"}),reportMissingResultsLinkText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText",message:"Let us know.",description:"The text for the link to report missing results"})}},placeholder:(0,c.I)({id:"theme.SearchModal.placeholder",message:"Search docs",description:"The placeholder of the input of the DocSearch pop-up modal"})};let Pe=null;function Ne(e){let{hit:t,children:n}=e;return r.createElement(Q.Z,{to:t.url},n)}function Oe(e){let{state:t,onClose:n}=e;const a=(0,Te.M)();return r.createElement(Q.Z,{to:a(t.query),onClick:n},r.createElement(c.Z,{id:"theme.SearchBar.seeAll",values:{count:t.context.nbHits}},"See all {count} results"))}function Ie(e){let{contextualSearch:t,externalUrlRegex:a,...o}=e;const{siteMetadata:i}=(0,se.Z)(),c=(0,Ce.l)(),u=function(){const{locale:e,tags:t}=(0,Ae._q)();return[`language:${e}`,t.map((e=>`docusaurus_tag:${e}`))]}(),d=o.searchParameters?.facetFilters??[],p=t?function(e,t){const n=e=>"string"==typeof e?[e]:e;return[...n(e),...n(t)]}(u,d):d,f={...o.searchParameters,facetFilters:p},m=(0,s.k6)(),h=(0,r.useRef)(null),g=(0,r.useRef)(null),[b,v]=(0,r.useState)(!1),[y,w]=(0,r.useState)(void 0),k=(0,r.useCallback)((()=>Pe?Promise.resolve():Promise.all([n.e(1426).then(n.bind(n,1426)),Promise.all([n.e(3312),n.e(6945)]).then(n.bind(n,6945)),Promise.all([n.e(3312),n.e(8894)]).then(n.bind(n,8894))]).then((e=>{let[{DocSearchModal:t}]=e;Pe=t}))),[]),_=(0,r.useCallback)((()=>{k().then((()=>{h.current=document.createElement("div"),document.body.insertBefore(h.current,document.body.firstChild),v(!0)}))}),[k,v]),S=(0,r.useCallback)((()=>{v(!1),h.current?.remove()}),[v]),E=(0,r.useCallback)((e=>{k().then((()=>{v(!0),w(e.key)}))}),[k,v,w]),x=(0,r.useRef)({navigate(e){let{itemUrl:t}=e;(0,ee.F)(a,t)?window.location.href=t:m.push(t)}}).current,T=(0,r.useRef)((e=>o.transformItems?o.transformItems(e):e.map((e=>({...e,url:c(e.url)}))))).current,C=(0,r.useMemo)((()=>e=>r.createElement(Oe,(0,l.Z)({},e,{onClose:S}))),[S]),A=(0,r.useCallback)((e=>(e.addAlgoliaAgent("docusaurus",i.docusaurusVersion),e)),[i.docusaurusVersion]);return function(e){var t=e.isOpen,n=e.onOpen,a=e.onClose,o=e.onInput,i=e.searchButtonRef;r.useEffect((function(){function e(e){var r;(27===e.keyCode&&t||"k"===(null===(r=e.key)||void 0===r?void 0:r.toLowerCase())&&(e.metaKey||e.ctrlKey)||!function(e){var t=e.target,n=t.tagName;return t.isContentEditable||"INPUT"===n||"SELECT"===n||"TEXTAREA"===n}(e)&&"/"===e.key&&!t)&&(e.preventDefault(),t?a():document.body.classList.contains("DocSearch--active")||document.body.classList.contains("DocSearch--active")||n()),i&&i.current===document.activeElement&&o&&/[a-zA-Z0-9]/.test(String.fromCharCode(e.keyCode))&&o(e)}return window.addEventListener("keydown",e),function(){window.removeEventListener("keydown",e)}}),[t,n,a,o,i])}({isOpen:b,onOpen:_,onClose:S,onInput:E,searchButtonRef:g}),r.createElement(r.Fragment,null,r.createElement(xe.Z,null,r.createElement("link",{rel:"preconnect",href:`https://${o.appId}-dsn.algolia.net`,crossOrigin:"anonymous"})),r.createElement(Ee,{onTouchStart:k,onFocus:k,onMouseOver:k,onClick:_,ref:g,translations:Re.button}),b&&Pe&&h.current&&(0,Le.createPortal)(r.createElement(Pe,(0,l.Z)({onClose:S,initialScrollY:window.scrollY,initialQuery:y,navigator:x,transformItems:T,hitComponent:Ne,transformSearchClient:A},o.searchPagePath&&{resultsFooterComponent:C},o,{searchParameters:f,placeholder:Re.placeholder,translations:Re.modal})),h.current))}function De(){const{siteConfig:e}=(0,se.Z)();return r.createElement(Ie,e.themeConfig.algolia)}const Me={searchBox:"searchBox_ZlJk"};function Be(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,Me.searchBox)},t)}var Fe=n(143),je=n(2802);var Ue=n(373);const ze=e=>e.docs.find((t=>t.id===e.mainDocId));const $e={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:d}}=(0,se.Z)(),p=(0,fe.l)(),{search:f,hash:m}=(0,s.TH)(),h=[...n,...u.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],g=t?(0,c.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(pe,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(me,{className:he}),g),items:h}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(Be,{className:n},r.createElement(De,null))},dropdown:pe,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,Fe.Iw)(a),s=(0,je.vY)(t,a);return null===s?null:r.createElement(oe,(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,Fe.Iw)(a),s=(0,je.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(oe,(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,je.lO)(a)[0],s=t??i.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(oe,(0,l.Z)({},o,{label:s,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...u}=e;const{search:d,hash:p}=(0,s.TH)(),f=(0,Fe.Iw)(n),m=(0,Fe.gB)(n),{savePreferredVersionName:h}=(0,Ue.J)(n),g=[...o,...m.map((e=>{const t=f.alternateDocVersions[e.name]??ze(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>h(e.name)}})),...i],b=(0,je.lO)(n)[0],v=t&&g.length>1?(0,c.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&g.length>1?void 0:ze(b).path;return g.length<=1?r.createElement(oe,(0,l.Z)({},u,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(pe,(0,l.Z)({},u,{mobile:t,label:v,to:y,items:g,isActive:a?()=>!1:void 0}))}};function qe(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=$e[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function He(){const e=(0,L.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(qe,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ge(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.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 Ze(){const e=0===(0,w.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Ge,{onClick:()=>t.hide()}),t.content)}function Ve(){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(B,{header:r.createElement(Y,null),primaryMenu:r.createElement(He,null),secondaryMenu:r.createElement(Ze,null)}):null}const We={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ke(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Ye(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,R.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i<o.current)return void n(!0);if(a.current)return void(a.current=!1);const l=r?.scrollY,s=document.documentElement.scrollHeight-o.current,c=window.innerHeight;l&&i>=l?n(!1):i+c<s&&n(!0)})),(0,u.S)((t=>{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,"aria-label":(0,c.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[We.navbarHideable,!s&&We.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Ke,{onClick:i.toggle}),r.createElement(Ve,null))}var Qe=n(8780);const Xe={errorBoundaryError:"errorBoundaryError_a6uf"};function Je(e){return r.createElement("button",(0,l.Z)({type:"button"},e),r.createElement(c.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function et(e){let{error:t}=e;const n=(0,Qe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{className:Xe.errorBoundaryError},n)}class tt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const nt="right";function rt(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 at(){const{toggle:e,shown:t}=(0,L.e)();return r.createElement("button",{onClick:e,"aria-label":(0,c.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(rt,null))}const ot={colorModeToggle:"colorModeToggle_DEke"};function it(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(tt,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},r.createElement(qe,e)))))}function lt(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 st(){const e=(0,L.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??nt)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement(lt,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(at,null),r.createElement(W,null),r.createElement(it,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(it,{items:a}),r.createElement(Z,{className:ot.colorModeToggle}),!o&&r.createElement(Be,null,r.createElement(De,null)))})}function ct(){return r.createElement(Ye,null,r.createElement(st,null))}function ut(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,c=(0,X.Z)(n),u=(0,X.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(Q.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?u:a}:{to:c},s),o,a&&!(0,J.Z)(a)&&r.createElement(te.Z,null))}function dt(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(ut,{item:t}))}function pt(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(dt,{key:t,item:e})))))}function ft(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(pt,{key:t,column:e}))))}function mt(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function ht(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(ut,{item:t})}function gt(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(ht,{item:e}),t.length!==n+1&&r.createElement(mt,null))))))}function bt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(ft,{columns:t}):r.createElement(gt,{links:t})}var vt=n(941);const yt={footerLogoLink:"footerLogoLink_BH7S"};function wt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,X.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(vt.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function kt(e){let{logo:t}=e;return t.href?r.createElement(Q.Z,{href:t.href,className:yt.footerLogoLink,target:t.target},r.createElement(wt,{logo:t})):r.createElement(wt,{logo:t})}function _t(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function St(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 Et(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(St,{style:o,links:n&&n.length>0&&r.createElement(bt,{links:n}),logo:a&&r.createElement(kt,{logo:a}),copyright:t&&r.createElement(_t,{copyright:t})})}const xt=r.memo(Et),Tt=(0,P.Qc)([F.S,k.pl,R.OC,Ue.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 Ct(e){let{children:t}=e;return r.createElement(Tt,null,t)}function At(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("div",{className:"margin-vert--lg"},r.createElement(Je,{onClick:n,className:"button button--primary shadow--lw"})),r.createElement("hr",null),r.createElement("div",{className:"margin-vert--md"},r.createElement(et,{error:t})))))}const Lt={mainWrapper:"mainWrapper_z2l0"};function Rt(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:c}=e;return(0,b.t)(),r.createElement(Ct,null,r.createElement(i.d,{title:s,description:c}),r.createElement(y,null),r.createElement(A,null),r.createElement(ct,null),r.createElement("div",{id:d,className:(0,a.Z)(g.k.wrapper.main,Lt.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(At,e)},t)),!n&&r.createElement(xt,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),c=n(941);function u(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(c.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:c}}=(0,s.L)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,i.Z)(c?.href||"/"),h=n?"":t,g=c?.alt??h;return a.createElement(o.Z,(0,r.Z)({to:m},f,c?.target&&{target:c.target}),c&&a.createElement(u,{logo:c,alt:g,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},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:()=>c});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 c(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:c,className:u,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:c[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],u)},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"},c={display:"block",overflow:"visible",height:"auto"};function u(e,t){const n=t?s:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return 0;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}function p(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=function(){const t=e.scrollHeight;return{transition:`height ${r?.duration??d(t)}ms ${r?.easing??i}`,height:`${t}px`}}();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return u(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(a(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{a()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function f(e){if(!o.Z.canUseDOM)return e?s:c}function m(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const c=(0,a.useRef)(null);return p({collapsibleRef:c,collapsed:n,animation:o}),a.createElement(t,{ref:c,style:s?void 0:f(n),onTransitionEnd:e=>{"height"===e.propertyName&&(u(c.current,n),i?.(n))},className:l},r)}function h(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(m,(0,r.Z)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?h:m;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.WA)("docusaurus.announcement.dismiss"),c=(0,o.WA)("docusaurus.announcement.id"),u=()=>"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&&u()));(0,r.useEffect)((()=>{o(u())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&d(!1),!r&&u()||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:()=>g,S:()=>h});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),c="theme",u=(0,i.WA)(c),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=>{u.set(p(e))};function h(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&&u.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),u.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!==c)return;const t=u.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 g(){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:()=>g,Oh:()=>y});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(2802),s=n(902),c=n(12);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.WA)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.WA)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.WA)(u(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 h(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function g(e){let{children:t}=e;return l.cE?r.createElement(h,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])}}function y(){const e=(0,a._r)(),[t]=b();function n(n){const r=e[n],{preferredVersionName:a}=t[n];return r.versions.find((e=>e.name===a))??null}const r=Object.keys(e);return Object.fromEntries(r.map((e=>[e,n(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}},3163:(e,t,n)=>{"use strict";n.d(t,{M:()=>d,e:()=>p});var r=n(7294),a=n(3102),o=n(7524),i=n(1980),l=n(6668),s=n(902);const c=r.createContext(void 0);function u(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.i)(),n=!e&&"mobile"===t,[s,c]=(0,r.useState)(!1);(0,i.Rb)((()=>{if(s)return c(!1),!1}));const u=(0,r.useCallback)((()=>{c((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&c(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:s})),[e,n,u,s])}function d(e){let{children:t}=e;const n=u();return r.createElement(c.Provider,{value:n},t)}function p(){const e=r.useContext(c);if(void 0===e)throw new s.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}},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)}}),[])}},6177:(e,t,n)=>{"use strict";n.d(t,{K:()=>l,M:()=>s});var r=n(7294),a=n(2263),o=n(1980);const i="q";function l(){return(0,o.Nc)(i)}function s(){const{siteConfig:{baseUrl:e,themeConfig:t}}=(0,a.Z)(),{algolia:{searchPagePath:n}}=t;return(0,r.useCallback)((t=>`${e}${n}?${i}=${encodeURIComponent(t)}`),[e,n])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>c});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 c(){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:{}}},2802:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>p,_F:()=>h,cE:()=>d,hI:()=>k,lO:()=>v,vY:()=>w,oz:()=>y,s1:()=>b});var r=n(7294),a=n(6550),o=n(8790),i=n(143),l=n(373),s=n(1116);function c(e){return Array.from(new Set(e))}var u=n(8596);const d=!!i._r;function p(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=p(t);if(e)return e}}}const f=(e,t)=>void 0!==e&&(0,u.Mg)(e,t),m=(e,t)=>e.some((e=>h(e,t)));function h(e,t){return"link"===e.type?f(e.href,t):"category"===e.type&&(f(e.href,t)||m(e.items,t))}function g(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,u.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,u.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function b(){const e=(0,s.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?g({sidebarItems:e.items,pathname:t}):null}function v(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>c([t,n,a].filter(Boolean))),[t,n,a])}function y(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function w(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${c(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function k(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,c=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:c}}},2128:(e,t,n)=>{"use strict";n.d(t,{p:()=>a});var r=n(2263);function a(e){const{siteConfig:t}=(0,r.Z)(),{title:n,titleDelimiter:a}=t;return e?.trim().length?`${e.trim()} ${a} ${n}`:n}},1980:(e,t,n)=>{"use strict";n.d(t,{Nc:()=>c,Rb:()=>l});var r=n(7294),a=n(6550),o=n(1688),i=n(902);function l(e){!function(e){const t=(0,a.k6)(),n=(0,i.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function s(e){return function(e){const t=(0,a.k6)();return(0,o.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}function c(e){const t=s(e)??"",n=function(){const e=(0,a.k6)();return(0,r.useCallback)(((t,n,r)=>{const a=new URLSearchParams(e.location.search);n?a.set(t,n):a.delete(t),(r?.push?e.push:e.replace)({search:a.toString()})}),[e])}();return[t,(0,r.useCallback)(((t,r)=>{n(e,t,r)}),[n,e])]}},833:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>u,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),c=n(2128);function u(e){let{title:t,description:n,keywords:a,image:i,children:l}=e;const u=(0,c.p)(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,u),t&&r.createElement("meta",{property:"og:title",content:u}),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:()=>c,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+\.)?(?<name>\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 c(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8022:(e,t,n)=>{"use strict";function r(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}n.d(t,{F:()=>r})},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:()=>p,OC:()=>s,RF:()=>d});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 c(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const u=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),a=(0,r.useRef)(u()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();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=(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&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>i,_q:()=>s,os:()=>l});var r=n(143),a=n(2263),o=n(373);const i="default";function l(e,t){return`docs-${e}-${t}`}function s(){const{i18n:e}=(0,a.Z)(),t=(0,r._r)(),n=(0,r.WS)(),s=(0,o.Oh)();const c=[i,...Object.keys(t).map((function(e){const r=n?.activePlugin.pluginId===e?n.activeVersion:void 0,a=s[e],o=t[e].versions.find((e=>e.isLast));return l(e,(r??a??o).name)}))];return{locale:e.currentLocale,tags:c}}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>s});n(7294),n(1688);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(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),i=!0),null}var t}let i=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function s(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,listen:t}}(e);const n=o(t?.persistence);return null===n?l:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"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}},6278:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){const{siteConfig:{themeConfig:e}}=(0,r.Z)();return e}},239:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(7294),a=n(8022),o=n(4996),i=n(6278);function l(){const{withBaseUrl:e}=(0,o.C)(),{algolia:{externalUrlRegex:t,replaceSearchResultPathname:n}}=(0,i.L)();return(0,r.useCallback)((r=>{const o=new URL(r);if((0,a.F)(t,o.href))return r;const i=`${o.pathname+o.hash}`;return e(function(e,t){return t?e.replaceAll(new RegExp(t.from,"g"),t.to):e}(i,n))}),[e,t,n])}},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)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},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.getErrorCausalChain=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}});var o=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},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;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{Z:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>w,q_:()=>T,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<a;n+=1,r+=1)e[n]=e[r];e.pop()}const i=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],i=t&&t.split("/")||[],l=e&&a(e),s=t&&a(t),c=l||s;if(e&&a(e)?i=r:r.length&&(i.pop(),i=i.concat(r)),!i.length)return"/";if(i.length){var u=i[i.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=i.length;p>=0;p--){var f=i[p];"."===f?o(i,p):".."===f?(o(i,p),d++):d&&(o(i,p),d--)}if(!c)for(;d--;d)i.unshift("..");!c||""===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 c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function 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;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),h||(0,l.Z)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,o=!(-1===window.navigator.userAgent.indexOf("Trident")),i=e,c=i.forceRefresh,w=void 0!==c&&c,k=i.getUserConfirmation,_=void 0===k?g:k,S=i.keyLength,E=void 0===S?6:S,x=e.basename?d(s(e.basename)):"";function T(e){var t=e||{},n=t.key,r=t.state,a=window.location,o=a.pathname+a.search+a.hash;return x&&(o=u(o,x)),f(o,r,n)}function C(){return Math.random().toString(36).substr(2,E)}var A=m();function L(e){(0,r.Z)(z,e),z.length=n.length,A.notifyListeners(z.location,z.action)}function R(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||O(T(e.state))}function P(){O(T(y()))}var N=!1;function O(e){if(N)N=!1,L();else{A.confirmTransitionTo(e,"POP",_,(function(t){t?L({action:"POP",location:e}):function(e){var t=z.location,n=D.indexOf(t.key);-1===n&&(n=0);var r=D.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(N=!0,B(a))}(e)}))}}var I=T(y()),D=[I.key];function M(e){return x+p(e)}function B(e){n.go(e)}var F=0;function j(e){1===(F+=e)&&1===e?(window.addEventListener(b,R),o&&window.addEventListener(v,P)):0===F&&(window.removeEventListener(b,R),o&&window.removeEventListener(v,P))}var U=!1;var z={length:n.length,action:"POP",location:I,createHref:M,push:function(e,t){var r="PUSH",o=f(e,t,C(),z.location);A.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.pushState({key:i,state:l},null,t),w)window.location.href=t;else{var s=D.indexOf(z.location.key),c=D.slice(0,s+1);c.push(o.key),D=c,L({action:r,location:o})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",o=f(e,t,C(),z.location);A.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.replaceState({key:i,state:l},null,t),w)window.location.replace(t);else{var s=D.indexOf(z.location.key);-1!==s&&(D[s]=o.key),L({action:r,location:o})}else window.location.replace(t)}}))},go:B,goBack:function(){B(-1)},goForward:function(){B(1)},block:function(e){void 0===e&&(e=!1);var t=A.setPrompt(e);return U||(j(1),U=!0),function(){return U&&(U=!1,j(-1)),t()}},listen:function(e){var t=A.appendListener(e);return j(1),function(){j(-1),t()}}};return z}var k="hashchange",_={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:s},slash:{encodePath:s,decodePath:s}};function S(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function E(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function x(e){window.location.replace(S(window.location.href)+"#"+e)}function T(e){void 0===e&&(e={}),h||(0,l.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,o=void 0===a?g:a,i=n.hashType,c=void 0===i?"slash":i,b=e.basename?d(s(e.basename)):"",v=_[c],y=v.encodePath,w=v.decodePath;function T(){var e=w(E());return b&&(e=u(e,b)),f(e)}var C=m();function A(e){(0,r.Z)(U,e),U.length=t.length,C.notifyListeners(U.location,U.action)}var L=!1,R=null;function P(){var e,t,n=E(),r=y(n);if(n!==r)x(r);else{var a=T(),i=U.location;if(!L&&(t=a,(e=i).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(R===p(a))return;R=null,function(e){if(L)L=!1,A();else{var t="POP";C.confirmTransitionTo(e,t,o,(function(n){n?A({action:t,location:e}):function(e){var t=U.location,n=D.lastIndexOf(p(t));-1===n&&(n=0);var r=D.lastIndexOf(p(e));-1===r&&(r=0);var a=n-r;a&&(L=!0,M(a))}(e)}))}}(a)}}var N=E(),O=y(N);N!==O&&x(O);var I=T(),D=[p(I)];function M(e){t.go(e)}var B=0;function F(e){1===(B+=e)&&1===e?window.addEventListener(k,P):0===B&&window.removeEventListener(k,P)}var j=!1;var U={length:t.length,action:"POP",location:I,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=S(window.location.href)),n+"#"+y(b+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,U.location);C.confirmTransitionTo(r,n,o,(function(e){if(e){var t=p(r),a=y(b+t);if(E()!==a){R=t,function(e){window.location.hash=e}(a);var o=D.lastIndexOf(p(U.location)),i=D.slice(0,o+1);i.push(t),D=i,A({action:n,location:r})}else A()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,U.location);C.confirmTransitionTo(r,n,o,(function(e){if(e){var t=p(r),a=y(b+t);E()!==a&&(R=t,x(a));var o=D.indexOf(p(U.location));-1!==o&&(D[o]=t),A({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=C.setPrompt(e);return j||(F(1),j=!0),function(){return j&&(j=!1,F(-1)),t()}},listen:function(e){var t=C.appendListener(e);return F(1),function(){F(-1),t()}}};return U}function C(e,t,n){return Math.min(Math.max(e,t),n)}function A(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,o=void 0===a?["/"]:a,i=t.initialIndex,l=void 0===i?0:i,s=t.keyLength,c=void 0===s?6:s,u=m();function d(e){(0,r.Z)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function h(){return Math.random().toString(36).substr(2,c)}var g=C(l,0,o.length-1),b=o.map((function(e){return f(e,void 0,"string"==typeof e?h():e.key||h())})),v=p;function y(e){var t=C(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var w={length:b.length,action:"POP",location:b[g],index:g,entries:b,createHref:v,push:function(e,t){var r="PUSH",a=f(e,t,h(),w.location);u.confirmTransitionTo(a,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,h(),w.location);u.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<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},8679:(e,t,n)=>{"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 c=Object.defineProperty,u=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=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),h=s(n),g=0;g<i.length;++g){var b=i[g];if(!(o[b]||r&&r[b]||h&&h[b]||l&&l[b])){var v=p(n,b);try{c(t,b,v)}catch(y){}}}}return t}},1143:e=>{"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 c=[n,r,a,o,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},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:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?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),c=o.querySelector(r.barSelector),u=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,i(e,u,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*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");u(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),c=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),c!=document.body&&u(c,"nprogress-custom-parent"),c.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 c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);c(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<arguments.length;s++){for(var c in o=Object(arguments[s]))n.call(o,c)&&(l[c]=o[c]);if(t){i=t(o);for(var u=0;u<i.length;u++)r.call(o,i[u])&&(l[i[u]]=o[i[u]])}}return l}},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(l+=e.slice(i,f),i=f+d.length,p)l+=p[1];else{var m=e[i],h=n[2],g=n[3],b=n[4],v=n[5],y=n[6],w=n[7];l&&(r.push(l),l="");var k=null!=h&&null!=m&&m!==h,_="+"===y||"*"===y,S="?"===y||"*"===y,E=n[2]||u,x=b||v;r.push({name:g||o++,prefix:h||"",delimiter:E,optional:S,repeat:_,partial:k,asterisk:!!w,pattern:x?c(x):w?".*":"[^"+s(E)+"]+?"})}}return i<e.length&&(l+=e.substr(i)),l&&r.push(l),r}function i(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function l(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var o="",l=t||{},s=(a||{}).pretty?i:encodeURIComponent,c=0;c<e.length;c++){var u=e[c];if("string"!=typeof u){var d,p=l[u.name];if(null==p){if(u.optional){u.partial&&(o+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=s(p[f]),!n[c].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");o+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):s(p),!n[c].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');o+=u.prefix+d}}else o+=u}return o}}function s(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,o=!1!==n.end,i="",l=0;l<e.length;l++){var c=e[l];if("string"==typeof c)i+=s(c);else{var p=s(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+p+f+")*"),i+=f=c.optional?c.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var m=s(n.delimiter||"/"),h=i.slice(-m.length)===m;return a||(i=(h?i.slice(0,-m.length):i)+"(?:"+m+"(?=$))?"),i+=o?"$":a&&h?"":"(?="+m+"|$)",u(new RegExp("^"+i,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(f(e[a],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(o(e,n),t,n)}(e,t,n)}},7410:(e,t,n)=>{"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(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,o;switch(n=n||{},r.util.type(t)){case"Object":if(o=r.util.objId(t),n[o])return n[o];for(var i in a={},n[o]=a,t)t.hasOwnProperty(i)&&(a[i]=e(t[i],n));return a;case"Array":return o=r.util.objId(t),n[o]?n[o]:(a=[],n[o]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var o=(a=a||r.languages)[e],i={};for(var l in o)if(o.hasOwnProperty(l)){if(l==t)for(var s in n)n.hasOwnProperty(s)&&(i[s]=n[s]);n.hasOwnProperty(l)||(i[l]=o[l])}var c=a[e];return a[e]=i,r.languages.DFS(r.languages,(function(t,n){n===c&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,a,o){o=o||{};var i=r.util.objId;for(var l in t)if(t.hasOwnProperty(l)){n.call(t,l,t[l],a||l);var s=t[l],c=r.util.type(s);"Object"!==c||o[i(s)]?"Array"!==c||o[i(s)]||(o[i(s)]=!0,e(s,n,l,o)):(o[i(s)]=!0,e(s,n,null,o))}}},plugins:{},highlight:function(e,t,n){var o={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",o),o.tokens=r.tokenize(o.code,o.grammar),r.hooks.run("after-tokenize",o),a.stringify(r.util.encode(o.tokens),o.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new l;return s(a,a.head,e),i(e,a,t,a.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,o=0;a=n[o++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function o(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var o=a[1].length;a.index+=o,a[0]=a[0].slice(o)}return a}function i(e,t,n,l,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(d&&d.cause==p+","+m)return;var h=f[m],g=h.inside,b=!!h.lookbehind,v=!!h.greedy,y=h.alias;if(v&&!h.pattern.global){var w=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,w+"g")}for(var k=h.pattern||h,_=l.next,S=u;_!==t.tail&&!(d&&S>=d.reach);S+=_.value.length,_=_.next){var E=_.value;if(t.length>e.length)return;if(!(E instanceof a)){var x,T=1;if(v){if(!(x=o(k,S,e,b))||x.index>=e.length)break;var C=x.index,A=x.index+x[0].length,L=S;for(L+=_.value.length;C>=L;)L+=(_=_.next).value.length;if(S=L-=_.value.length,_.value instanceof a)continue;for(var R=_;R!==t.tail&&(L<A||"string"==typeof R.value);R=R.next)T++,L+=R.value.length;T--,E=e.slice(S,L),x.index-=S}else if(!(x=o(k,0,E,b)))continue;C=x.index;var P=x[0],N=E.slice(0,C),O=E.slice(C+P.length),I=S+E.length;d&&I>d.reach&&(d.reach=I);var D=_.prev;if(N&&(D=s(t,D,N),S+=N.length),c(t,D,T),_=s(t,D,new a(p,g?r.tokenize(P,g):P,y,P)),O&&s(t,_,O),T>1){var M={cause:p+","+m,reach:I};i(e,t,n,_.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 c(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var o={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(o.classes,i):o.classes.push(i)),r.hooks.run("wrap",o);var l="";for(var s in o.attributes)l+=" "+s+'="'+(o.attributes[s]||"").replace(/"/g,""")+'"';return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+l+">"+o.content+"</"+o.tag+">"},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},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:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.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<a.length;i++)o[a[i]]=e.languages.bash[a[i]];e.languages.shell=e.languages.bash}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},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(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(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]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/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<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+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(/<inner>/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__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a=t[n];if("code"===a.type){var o=a.content[1],i=a.content[3];if(o&&i&&"code-language"===o.type&&"code-block"===i.type&&"string"==typeof o.content){var l=o.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),s="language-"+(l=(/[a-z][\w-]*/i.exec(l)||[""])[0].toLowerCase());i.alias?"string"==typeof i.alias?i.alias=[i.alias,s]:i.alias.push(s):i.alias=[s]}}else e(a.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var o=t.classes[r],c=/language-(.+)/.exec(o);if(c){n=c[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(i,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),s(n);var r=l[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var p="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=p,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(p);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var i=RegExp(e.languages.markup.tag.pattern.source,"gi"),l={amp:"&",lt:"<",gt:">",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;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var o=p(/^\($/,/^\)$/);if(-1===o)continue;for(;n<o;n++){var i=u(0);"variable"===i.type&&(f(i,"variable-input"),a.push(i.content))}n=o+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),a.length>0)){var l=p(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s<l;s++){var c=t[s];"variable"===c.type&&a.indexOf(c.content)>=0&&f(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return!1}return!0}function p(e,r){for(var a=1,o=n;o<t.length;o++){var i=t[o],l=i.content;if("punctuation"===i.type&&"string"==typeof l)if(e.test(l))a++;else if(r.test(l)&&0===--a)return o}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,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 c(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 u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,u={},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 u[n]=a,n})).join(""),n,r),p=Object.keys(u);return i=0,function e(t){for(var n=0;n<t.length;n++){if(i>=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=c(u[a]),f=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),f){var h=[f];e(h),m.push.apply(m,h)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(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<a;r++){var o=n[r];if("string"!=typeof o){var i=o.content;if(Array.isArray(i))if("template-string"===o.type){var l=i[1];if(3===i.length&&"string"!=typeof l&&"embedded-code"===l.type){var s=p(l),c=l.alias,d=Array.isArray(c)?c[0]:c,f=e.languages[d];if(!f)continue;i[1]=u(s,f,d)}}else t(i);else"string"!=typeof i&&t([i])}}}(t.tokens)}))}(a),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],o=e.languages.javascript[a];"RegExp"===e.util.type(o)&&(o=e.languages.javascript[a]={pattern:o});var i=o.inside||{};o.inside=i,i["maybe-class-name"]=/^[A-Z][\s\S]*/}}(a),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function o(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/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.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=<BRACES>/.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;r<t.length;r++){var a=t[r],o=!1;if("string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?n.length>0&&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);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(s+=i(t[r+1]),t.splice(r+1,1)),r>0&&("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<l.length&&!(a>=o.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=o[a],d=n.tokenStack[u],p="string"==typeof c?c:c.content,f=t(r,u),m=p.indexOf(f);if(m>-1){++a;var h=p.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(m+f.length),v=[];h&&v.push.apply(v,i([h])),v.push(g),b&&v.push.apply(v,i([b])),"string"==typeof c?l.splice.apply(l,[s,1].concat(v)):c.content=v}}else c.content&&i(c.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 <a href="https://webplatform.github.io/docs/">WebPlatform.org documentation</a>. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (<code>.comment</code> can become <code>.namespace--comment</code>) or replace them with your defined ones (like <code>.editor__comment</code>). 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 <code>highlightAll</code> and <code>highlightAllUnder</code> 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<r;n++)t[e[n]]=!0;return t}function r(e){var n={},r=[];function a(r,o){if(!(r in n)){o.push(r);var i=o.indexOf(r);if(i<o.length-1)throw new Error("Circular dependency: "+o.slice(i).join(" -> "));var l={},s=e[r];if(s){function c(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,c),t(s.optional,c),t(s.modify,c)}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),c=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(c),l=(l||[]).map(c);var u=n(i),d=n(l);i.forEach((function e(n){var r=s[n];t(r&&r.require,(function(t){t in d||(u[t]=!0,e(t))}))}));for(var p,f=r(s),m=u;a(m);){for(var h in p={},m){var g=s[h];t(g&&g.modify,(function(e){e in d&&(p[e]=!0)}))}for(var b in d)if(!(b in u))for(var v in f(b))if(v in u){p[b]=!0;break}for(var y in m=p)u[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 c(e){if(e in l)return l[e];s[e]=!0;var a,u=[];for(var d in t(e))d in n&&u.push(d);if(0===u.length)a=r(e);else{var p=i(u.map((function(e){var t=c(e);return delete s[e],t})));o?a=o(p,(function(){return r(e)})):r(e)}return l[e]=a}for(var u in n)c(u);var d=[];for(var p in s)d.push(l[p]);return i(d)}(f,u,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(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(i(227));var l=new Set,s={};function c(e,t){u(e,t),u(e+"Capture",t)}function u(e,t){for(s[e]=t,e=0;e<t.length;e++)l.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),p=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f=Object.prototype.hasOwnProperty,m={},h={};function g(e,t,n,r,a,o,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){b[e]=new g(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];b[t]=new g(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){b[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){b[e]=new g(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){b[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){b[e]=new g(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){b[e]=new g(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){b[e]=new g(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){b[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)}));var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}function w(e,t,n,r){var a=b.hasOwnProperty(t)?b[t]:null;(null!==a?0===a.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!f.call(h,e)||!f.call(m,e)&&(p.test(e)?h[e]=!0:(m[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)})),b.xlinkHref=new g("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)}));var k=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,_=60103,S=60106,E=60107,x=60108,T=60114,C=60109,A=60110,L=60112,R=60113,P=60120,N=60115,O=60116,I=60121,D=60128,M=60129,B=60130,F=60131;if("function"==typeof Symbol&&Symbol.for){var j=Symbol.for;_=j("react.element"),S=j("react.portal"),E=j("react.fragment"),x=j("react.strict_mode"),T=j("react.profiler"),C=j("react.provider"),A=j("react.context"),L=j("react.forward_ref"),R=j("react.suspense"),P=j("react.suspense_list"),N=j("react.memo"),O=j("react.lazy"),I=j("react.block"),j("react.scope"),D=j("react.opaque.id"),M=j("react.debug_trace_mode"),B=j("react.offscreen"),F=j("react.legacy_hidden")}var U,z="function"==typeof Symbol&&Symbol.iterator;function $(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=z&&e[z]||e["@@iterator"])?e:null}function q(e){if(void 0===U)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);U=t&&t[1]||""}return"\n"+U+e}var H=!1;function G(e,t){if(!e||H)return"";H=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(s){var r=s}Reflect.construct(e,[],t)}else{try{t.call()}catch(s){r=s}e.call(t.prototype)}else{try{throw Error()}catch(s){r=s}e()}}catch(s){if(s&&r&&"string"==typeof s.stack){for(var a=s.stack.split("\n"),o=r.stack.split("\n"),i=a.length-1,l=o.length-1;1<=i&&0<=l&&a[i]!==o[l];)l--;for(;1<=i&&0<=l;i--,l--)if(a[i]!==o[l]){if(1!==i||1!==l)do{if(i--,0>--l||a[i]!==o[l])return"\n"+a[i].replace(" at new "," at ")}while(1<=i&&0<=l);break}}}finally{H=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?q(e):""}function Z(e){switch(e.tag){case 5:return q(e.type);case 16:return q("Lazy");case 13:return q("Suspense");case 19:return q("SuspenseList");case 0:case 2:case 15:return e=G(e.type,!1);case 11:return e=G(e.type.render,!1);case 22:return e=G(e.type._render,!1);case 1:return e=G(e.type,!0);default:return""}}function V(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case E:return"Fragment";case S:return"Portal";case T:return"Profiler";case x:return"StrictMode";case R:return"Suspense";case P:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case A:return(e.displayName||"Context")+".Consumer";case C:return(e._context.displayName||"Context")+".Provider";case L:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case N:return V(e.type);case I:return V(e._render);case O:t=e._payload,e=e._init;try{return V(e(t))}catch(n){}}return null}function W(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function K(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function Y(e){e._valueTracker||(e._valueTracker=function(e){var t=K(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function Q(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=K(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function X(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function J(e,t){var n=t.checked;return a({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=W(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function te(e,t){null!=(t=t.checked)&&w(e,"checked",t,!1)}function ne(e,t){te(e,t);var n=W(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ae(e,t.type,n):t.hasOwnProperty("defaultValue")&&ae(e,t.type,W(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function re(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ae(e,t,n){"number"===t&&X(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function oe(e,t){return e=a({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function ie(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+W(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function le(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(i(91));return a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function se(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(i(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(i(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:W(n)}}function ce(e,t){var n=W(t.value),r=W(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ue(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var de={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function pe(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function fe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?pe(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var me,he,ge=(he=function(e,t){if(e.namespaceURI!==de.svg||"innerHTML"in e)e.innerHTML=t;else{for((me=me||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return he(e,t)}))}:he);function be(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var ve={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ye=["Webkit","ms","Moz","O"];function we(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||ve.hasOwnProperty(e)&&ve[e]?(""+t).trim():t+"px"}function ke(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=we(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(ve).forEach((function(e){ye.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ve[t]=ve[e]}))}));var _e=a({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Se(e,t){if(t){if(_e[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(i(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(i(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(i(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(i(62))}}function Ee(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function xe(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var Te=null,Ce=null,Ae=null;function Le(e){if(e=na(e)){if("function"!=typeof Te)throw Error(i(280));var t=e.stateNode;t&&(t=aa(t),Te(e.stateNode,e.type,t))}}function Re(e){Ce?Ae?Ae.push(e):Ae=[e]:Ce=e}function Pe(){if(Ce){var e=Ce,t=Ae;if(Ae=Ce=null,Le(e),t)for(e=0;e<t.length;e++)Le(t[e])}}function Ne(e,t){return e(t)}function Oe(e,t,n,r,a){return e(t,n,r,a)}function Ie(){}var De=Ne,Me=!1,Be=!1;function Fe(){null===Ce&&null===Ae||(Ie(),Pe())}function je(e,t){var n=e.stateNode;if(null===n)return null;var r=aa(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(i(231,t,typeof n));return n}var Ue=!1;if(d)try{var ze={};Object.defineProperty(ze,"passive",{get:function(){Ue=!0}}),window.addEventListener("test",ze,ze),window.removeEventListener("test",ze,ze)}catch(he){Ue=!1}function $e(e,t,n,r,a,o,i,l,s){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(u){this.onError(u)}}var qe=!1,He=null,Ge=!1,Ze=null,Ve={onError:function(e){qe=!0,He=e}};function We(e,t,n,r,a,o,i,l,s){qe=!1,He=null,$e.apply(Ve,arguments)}function Ke(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(1026&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Ye(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Qe(e){if(Ke(e)!==e)throw Error(i(188))}function Xe(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ke(e)))throw Error(i(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var o=a.alternate;if(null===o){if(null!==(r=a.return)){n=r;continue}break}if(a.child===o.child){for(o=a.child;o;){if(o===n)return Qe(a),e;if(o===r)return Qe(a),t;o=o.sibling}throw Error(i(188))}if(n.return!==r.return)n=a,r=o;else{for(var l=!1,s=a.child;s;){if(s===n){l=!0,n=a,r=o;break}if(s===r){l=!0,r=a,n=o;break}s=s.sibling}if(!l){for(s=o.child;s;){if(s===n){l=!0,n=o,r=a;break}if(s===r){l=!0,r=o,n=a;break}s=s.sibling}if(!l)throw Error(i(189))}}if(n.alternate!==r)throw Error(i(190))}if(3!==n.tag)throw Error(i(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function Je(e,t){for(var n=e.alternate;null!==t;){if(t===e||t===n)return!0;t=t.return}return!1}var et,tt,nt,rt,at=!1,ot=[],it=null,lt=null,st=null,ct=new Map,ut=new Map,dt=[],pt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function ft(e,t,n,r,a){return{blockedOn:e,domEventName:t,eventSystemFlags:16|n,nativeEvent:a,targetContainers:[r]}}function mt(e,t){switch(e){case"focusin":case"focusout":it=null;break;case"dragenter":case"dragleave":lt=null;break;case"mouseover":case"mouseout":st=null;break;case"pointerover":case"pointerout":ct.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":ut.delete(t.pointerId)}}function ht(e,t,n,r,a,o){return null===e||e.nativeEvent!==o?(e=ft(t,n,r,a,o),null!==t&&(null!==(t=na(t))&&tt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==a&&-1===t.indexOf(a)&&t.push(a),e)}function gt(e){var t=ta(e.target);if(null!==t){var n=Ke(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Ye(n)))return e.blockedOn=t,void rt(e.lanePriority,(function(){o.unstable_runWithPriority(e.priority,(function(){nt(n)}))}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function bt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Xt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=na(n))&&tt(t),e.blockedOn=n,!1;t.shift()}return!0}function vt(e,t,n){bt(e)&&n.delete(t)}function yt(){for(at=!1;0<ot.length;){var e=ot[0];if(null!==e.blockedOn){null!==(e=na(e.blockedOn))&&et(e);break}for(var t=e.targetContainers;0<t.length;){var n=Xt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n){e.blockedOn=n;break}t.shift()}null===e.blockedOn&&ot.shift()}null!==it&&bt(it)&&(it=null),null!==lt&&bt(lt)&&(lt=null),null!==st&&bt(st)&&(st=null),ct.forEach(vt),ut.forEach(vt)}function wt(e,t){e.blockedOn===t&&(e.blockedOn=null,at||(at=!0,o.unstable_scheduleCallback(o.unstable_NormalPriority,yt)))}function kt(e){function t(t){return wt(t,e)}if(0<ot.length){wt(ot[0],e);for(var n=1;n<ot.length;n++){var r=ot[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==it&&wt(it,e),null!==lt&&wt(lt,e),null!==st&&wt(st,e),ct.forEach(t),ut.forEach(t),n=0;n<dt.length;n++)(r=dt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<dt.length&&null===(n=dt[0]).blockedOn;)gt(n),null===n.blockedOn&&dt.shift()}function _t(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var St={animationend:_t("Animation","AnimationEnd"),animationiteration:_t("Animation","AnimationIteration"),animationstart:_t("Animation","AnimationStart"),transitionend:_t("Transition","TransitionEnd")},Et={},xt={};function Tt(e){if(Et[e])return Et[e];if(!St[e])return e;var t,n=St[e];for(t in n)if(n.hasOwnProperty(t)&&t in xt)return Et[e]=n[t];return e}d&&(xt=document.createElement("div").style,"AnimationEvent"in window||(delete St.animationend.animation,delete St.animationiteration.animation,delete St.animationstart.animation),"TransitionEvent"in window||delete St.transitionend.transition);var Ct=Tt("animationend"),At=Tt("animationiteration"),Lt=Tt("animationstart"),Rt=Tt("transitionend"),Pt=new Map,Nt=new Map,Ot=["abort","abort",Ct,"animationEnd",At,"animationIteration",Lt,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Rt,"transitionEnd","waiting","waiting"];function It(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],a=e[n+1];a="on"+(a[0].toUpperCase()+a.slice(1)),Nt.set(r,t),Pt.set(r,a),c(a,[r])}}(0,o.unstable_now)();var Dt=8;function Mt(e){if(0!=(1&e))return Dt=15,1;if(0!=(2&e))return Dt=14,2;if(0!=(4&e))return Dt=13,4;var t=24&e;return 0!==t?(Dt=12,t):0!=(32&e)?(Dt=11,32):0!==(t=192&e)?(Dt=10,t):0!=(256&e)?(Dt=9,256):0!==(t=3584&e)?(Dt=8,t):0!=(4096&e)?(Dt=7,4096):0!==(t=4186112&e)?(Dt=6,t):0!==(t=62914560&e)?(Dt=5,t):67108864&e?(Dt=4,67108864):0!=(134217728&e)?(Dt=3,134217728):0!==(t=805306368&e)?(Dt=2,t):0!=(1073741824&e)?(Dt=1,1073741824):(Dt=8,e)}function Bt(e,t){var n=e.pendingLanes;if(0===n)return Dt=0;var r=0,a=0,o=e.expiredLanes,i=e.suspendedLanes,l=e.pingedLanes;if(0!==o)r=o,a=Dt=15;else if(0!==(o=134217727&n)){var s=o&~i;0!==s?(r=Mt(s),a=Dt):0!==(l&=o)&&(r=Mt(l),a=Dt)}else 0!==(o=n&~i)?(r=Mt(o),a=Dt):0!==l&&(r=Mt(l),a=Dt);if(0===r)return 0;if(r=n&((0>(r=31-qt(r))?0:1<<r)<<1)-1,0!==t&&t!==r&&0==(t&i)){if(Mt(t),a<=Dt)return t;Dt=a}if(0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)a=1<<(n=31-qt(t)),r|=e[n],t&=~a;return r}function Ft(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function jt(e,t){switch(e){case 15:return 1;case 14:return 2;case 12:return 0===(e=Ut(24&~t))?jt(10,t):e;case 10:return 0===(e=Ut(192&~t))?jt(8,t):e;case 8:return 0===(e=Ut(3584&~t))&&(0===(e=Ut(4186112&~t))&&(e=512)),e;case 2:return 0===(t=Ut(805306368&~t))&&(t=268435456),t}throw Error(i(358,e))}function Ut(e){return e&-e}function zt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function $t(e,t,n){e.pendingLanes|=t;var r=t-1;e.suspendedLanes&=r,e.pingedLanes&=r,(e=e.eventTimes)[t=31-qt(t)]=n}var qt=Math.clz32?Math.clz32:function(e){return 0===e?32:31-(Ht(e)/Gt|0)|0},Ht=Math.log,Gt=Math.LN2;var Zt=o.unstable_UserBlockingPriority,Vt=o.unstable_runWithPriority,Wt=!0;function Kt(e,t,n,r){Me||Ie();var a=Qt,o=Me;Me=!0;try{Oe(a,e,t,n,r)}finally{(Me=o)||Fe()}}function Yt(e,t,n,r){Vt(Zt,Qt.bind(null,e,t,n,r))}function Qt(e,t,n,r){var a;if(Wt)if((a=0==(4&t))&&0<ot.length&&-1<pt.indexOf(e))e=ft(null,e,t,n,r),ot.push(e);else{var o=Xt(e,t,n,r);if(null===o)a&&mt(e,r);else{if(a){if(-1<pt.indexOf(e))return e=ft(o,e,t,n,r),void ot.push(e);if(function(e,t,n,r,a){switch(t){case"focusin":return it=ht(it,e,t,n,r,a),!0;case"dragenter":return lt=ht(lt,e,t,n,r,a),!0;case"mouseover":return st=ht(st,e,t,n,r,a),!0;case"pointerover":var o=a.pointerId;return ct.set(o,ht(ct.get(o)||null,e,t,n,r,a)),!0;case"gotpointercapture":return o=a.pointerId,ut.set(o,ht(ut.get(o)||null,e,t,n,r,a)),!0}return!1}(o,e,t,n,r))return;mt(e,r)}Ir(e,t,r,null,n)}}}function Xt(e,t,n,r){var a=xe(r);if(null!==(a=ta(a))){var o=Ke(a);if(null===o)a=null;else{var i=o.tag;if(13===i){if(null!==(a=Ye(o)))return a;a=null}else if(3===i){if(o.stateNode.hydrate)return 3===o.tag?o.stateNode.containerInfo:null;a=null}else o!==a&&(a=null)}}return Ir(e,t,r,a,n),null}var Jt=null,en=null,tn=null;function nn(){if(tn)return tn;var e,t,n=en,r=n.length,a="value"in Jt?Jt.value:Jt.textContent,o=a.length;for(e=0;e<r&&n[e]===a[e];e++);var i=r-e;for(t=1;t<=i&&n[r-t]===a[o-t];t++);return tn=a.slice(e,1<t?1-t:void 0)}function rn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function an(){return!0}function on(){return!1}function ln(e){function t(t,n,r,a,o){for(var i in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=a,this.target=o,this.currentTarget=null,e)e.hasOwnProperty(i)&&(t=e[i],this[i]=t?t(a):a[i]);return this.isDefaultPrevented=(null!=a.defaultPrevented?a.defaultPrevented:!1===a.returnValue)?an:on,this.isPropagationStopped=on,this}return a(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=an)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=an)},persist:function(){},isPersistent:an}),t}var sn,cn,un,dn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},pn=ln(dn),fn=a({},dn,{view:0,detail:0}),mn=ln(fn),hn=a({},fn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Cn,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==un&&(un&&"mousemove"===e.type?(sn=e.screenX-un.screenX,cn=e.screenY-un.screenY):cn=sn=0,un=e),sn)},movementY:function(e){return"movementY"in e?e.movementY:cn}}),gn=ln(hn),bn=ln(a({},hn,{dataTransfer:0})),vn=ln(a({},fn,{relatedTarget:0})),yn=ln(a({},dn,{animationName:0,elapsedTime:0,pseudoElement:0})),wn=a({},dn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),kn=ln(wn),_n=ln(a({},dn,{data:0})),Sn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},En={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},xn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Tn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=xn[e])&&!!t[e]}function Cn(){return Tn}var An=a({},fn,{key:function(e){if(e.key){var t=Sn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=rn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?En[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Cn,charCode:function(e){return"keypress"===e.type?rn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?rn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),Ln=ln(An),Rn=ln(a({},hn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Pn=ln(a({},fn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Cn})),Nn=ln(a({},dn,{propertyName:0,elapsedTime:0,pseudoElement:0})),On=a({},hn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),In=ln(On),Dn=[9,13,27,32],Mn=d&&"CompositionEvent"in window,Bn=null;d&&"documentMode"in document&&(Bn=document.documentMode);var Fn=d&&"TextEvent"in window&&!Bn,jn=d&&(!Mn||Bn&&8<Bn&&11>=Bn),Un=String.fromCharCode(32),zn=!1;function $n(e,t){switch(e){case"keyup":return-1!==Dn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function qn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Hn=!1;var Gn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Zn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Gn[e.type]:"textarea"===t}function Vn(e,t,n,r){Re(r),0<(t=Mr(t,"onChange")).length&&(n=new pn("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Wn=null,Kn=null;function Yn(e){Ar(e,0)}function Qn(e){if(Q(ra(e)))return e}function Xn(e,t){if("change"===e)return t}var Jn=!1;if(d){var er;if(d){var tr="oninput"in document;if(!tr){var nr=document.createElement("div");nr.setAttribute("oninput","return;"),tr="function"==typeof nr.oninput}er=tr}else er=!1;Jn=er&&(!document.documentMode||9<document.documentMode)}function rr(){Wn&&(Wn.detachEvent("onpropertychange",ar),Kn=Wn=null)}function ar(e){if("value"===e.propertyName&&Qn(Kn)){var t=[];if(Vn(t,Kn,e,xe(e)),e=Yn,Me)e(t);else{Me=!0;try{Ne(e,t)}finally{Me=!1,Fe()}}}}function or(e,t,n){"focusin"===e?(rr(),Kn=n,(Wn=t).attachEvent("onpropertychange",ar)):"focusout"===e&&rr()}function ir(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Qn(Kn)}function lr(e,t){if("click"===e)return Qn(t)}function sr(e,t){if("input"===e||"change"===e)return Qn(t)}var cr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},ur=Object.prototype.hasOwnProperty;function dr(e,t){if(cr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!ur.call(t,n[r])||!cr(e[n[r]],t[n[r]]))return!1;return!0}function pr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function fr(e,t){var n,r=pr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=pr(r)}}function mr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function hr(){for(var e=window,t=X();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=X((e=t.contentWindow).document)}return t}function gr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var br=d&&"documentMode"in document&&11>=document.documentMode,vr=null,yr=null,wr=null,kr=!1;function _r(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;kr||null==vr||vr!==X(r)||("selectionStart"in(r=vr)&&gr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},wr&&dr(wr,r)||(wr=r,0<(r=Mr(yr,"onSelect")).length&&(t=new pn("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=vr)))}It("cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focusin focus focusout blur input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),It("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),It(Ot,2);for(var Sr="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),Er=0;Er<Sr.length;Er++)Nt.set(Sr[Er],0);u("onMouseEnter",["mouseout","mouseover"]),u("onMouseLeave",["mouseout","mouseover"]),u("onPointerEnter",["pointerout","pointerover"]),u("onPointerLeave",["pointerout","pointerover"]),c("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),c("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),c("onBeforeInput",["compositionend","keypress","textInput","paste"]),c("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var xr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Tr=new Set("cancel close invalid load scroll toggle".split(" ").concat(xr));function Cr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,a,o,l,s,c){if(We.apply(this,arguments),qe){if(!qe)throw Error(i(198));var u=He;qe=!1,He=null,Ge||(Ge=!0,Ze=u)}}(r,t,void 0,e),e.currentTarget=null}function Ar(e,t){t=0!=(4&t);for(var n=0;n<e.length;n++){var r=e[n],a=r.event;r=r.listeners;e:{var o=void 0;if(t)for(var i=r.length-1;0<=i;i--){var l=r[i],s=l.instance,c=l.currentTarget;if(l=l.listener,s!==o&&a.isPropagationStopped())break e;Cr(a,l,c),o=s}else for(i=0;i<r.length;i++){if(s=(l=r[i]).instance,c=l.currentTarget,l=l.listener,s!==o&&a.isPropagationStopped())break e;Cr(a,l,c),o=s}}}if(Ge)throw e=Ze,Ge=!1,Ze=null,e}function Lr(e,t){var n=oa(t),r=e+"__bubble";n.has(r)||(Or(t,e,2,!1),n.add(r))}var Rr="_reactListening"+Math.random().toString(36).slice(2);function Pr(e){e[Rr]||(e[Rr]=!0,l.forEach((function(t){Tr.has(t)||Nr(t,!1,e,null),Nr(t,!0,e,null)})))}function Nr(e,t,n,r){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,o=n;if("selectionchange"===e&&9!==n.nodeType&&(o=n.ownerDocument),null!==r&&!t&&Tr.has(e)){if("scroll"!==e)return;a|=2,o=r}var i=oa(o),l=e+"__"+(t?"capture":"bubble");i.has(l)||(t&&(a|=4),Or(o,e,a,t),i.add(l))}function Or(e,t,n,r){var a=Nt.get(t);switch(void 0===a?2:a){case 0:a=Kt;break;case 1:a=Yt;break;default:a=Qt}n=a.bind(null,t,n,e),a=void 0,!Ue||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(a=!0),r?void 0!==a?e.addEventListener(t,n,{capture:!0,passive:a}):e.addEventListener(t,n,!0):void 0!==a?e.addEventListener(t,n,{passive:a}):e.addEventListener(t,n,!1)}function Ir(e,t,n,r,a){var o=r;if(0==(1&t)&&0==(2&t)&&null!==r)e:for(;;){if(null===r)return;var i=r.tag;if(3===i||4===i){var l=r.stateNode.containerInfo;if(l===a||8===l.nodeType&&l.parentNode===a)break;if(4===i)for(i=r.return;null!==i;){var s=i.tag;if((3===s||4===s)&&((s=i.stateNode.containerInfo)===a||8===s.nodeType&&s.parentNode===a))return;i=i.return}for(;null!==l;){if(null===(i=ta(l)))return;if(5===(s=i.tag)||6===s){r=o=i;continue e}l=l.parentNode}}r=r.return}!function(e,t,n){if(Be)return e(t,n);Be=!0;try{return De(e,t,n)}finally{Be=!1,Fe()}}((function(){var r=o,a=xe(n),i=[];e:{var l=Pt.get(e);if(void 0!==l){var s=pn,c=e;switch(e){case"keypress":if(0===rn(n))break e;case"keydown":case"keyup":s=Ln;break;case"focusin":c="focus",s=vn;break;case"focusout":c="blur",s=vn;break;case"beforeblur":case"afterblur":s=vn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":s=gn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":s=bn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":s=Pn;break;case Ct:case At:case Lt:s=yn;break;case Rt:s=Nn;break;case"scroll":s=mn;break;case"wheel":s=In;break;case"copy":case"cut":case"paste":s=kn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":s=Rn}var u=0!=(4&t),d=!u&&"scroll"===e,p=u?null!==l?l+"Capture":null:l;u=[];for(var f,m=r;null!==m;){var h=(f=m).stateNode;if(5===f.tag&&null!==h&&(f=h,null!==p&&(null!=(h=je(m,p))&&u.push(Dr(m,h,f)))),d)break;m=m.return}0<u.length&&(l=new s(l,c,null,n,a),i.push({event:l,listeners:u}))}}if(0==(7&t)){if(s="mouseout"===e||"pointerout"===e,(!(l="mouseover"===e||"pointerover"===e)||0!=(16&t)||!(c=n.relatedTarget||n.fromElement)||!ta(c)&&!c[Jr])&&(s||l)&&(l=a.window===a?a:(l=a.ownerDocument)?l.defaultView||l.parentWindow:window,s?(s=r,null!==(c=(c=n.relatedTarget||n.toElement)?ta(c):null)&&(c!==(d=Ke(c))||5!==c.tag&&6!==c.tag)&&(c=null)):(s=null,c=r),s!==c)){if(u=gn,h="onMouseLeave",p="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(u=Rn,h="onPointerLeave",p="onPointerEnter",m="pointer"),d=null==s?l:ra(s),f=null==c?l:ra(c),(l=new u(h,m+"leave",s,n,a)).target=d,l.relatedTarget=f,h=null,ta(a)===r&&((u=new u(p,m+"enter",c,n,a)).target=f,u.relatedTarget=d,h=u),d=h,s&&c)e:{for(p=c,m=0,f=u=s;f;f=Br(f))m++;for(f=0,h=p;h;h=Br(h))f++;for(;0<m-f;)u=Br(u),m--;for(;0<f-m;)p=Br(p),f--;for(;m--;){if(u===p||null!==p&&u===p.alternate)break e;u=Br(u),p=Br(p)}u=null}else u=null;null!==s&&Fr(i,l,s,u,!1),null!==c&&null!==d&&Fr(i,d,c,u,!0)}if("select"===(s=(l=r?ra(r):window).nodeName&&l.nodeName.toLowerCase())||"input"===s&&"file"===l.type)var g=Xn;else if(Zn(l))if(Jn)g=sr;else{g=ir;var b=or}else(s=l.nodeName)&&"input"===s.toLowerCase()&&("checkbox"===l.type||"radio"===l.type)&&(g=lr);switch(g&&(g=g(e,r))?Vn(i,g,n,a):(b&&b(e,l,r),"focusout"===e&&(b=l._wrapperState)&&b.controlled&&"number"===l.type&&ae(l,"number",l.value)),b=r?ra(r):window,e){case"focusin":(Zn(b)||"true"===b.contentEditable)&&(vr=b,yr=r,wr=null);break;case"focusout":wr=yr=vr=null;break;case"mousedown":kr=!0;break;case"contextmenu":case"mouseup":case"dragend":kr=!1,_r(i,n,a);break;case"selectionchange":if(br)break;case"keydown":case"keyup":_r(i,n,a)}var v;if(Mn)e:{switch(e){case"compositionstart":var y="onCompositionStart";break e;case"compositionend":y="onCompositionEnd";break e;case"compositionupdate":y="onCompositionUpdate";break e}y=void 0}else Hn?$n(e,n)&&(y="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(y="onCompositionStart");y&&(jn&&"ko"!==n.locale&&(Hn||"onCompositionStart"!==y?"onCompositionEnd"===y&&Hn&&(v=nn()):(en="value"in(Jt=a)?Jt.value:Jt.textContent,Hn=!0)),0<(b=Mr(r,y)).length&&(y=new _n(y,e,null,n,a),i.push({event:y,listeners:b}),v?y.data=v:null!==(v=qn(n))&&(y.data=v))),(v=Fn?function(e,t){switch(e){case"compositionend":return qn(t);case"keypress":return 32!==t.which?null:(zn=!0,Un);case"textInput":return(e=t.data)===Un&&zn?null:e;default:return null}}(e,n):function(e,t){if(Hn)return"compositionend"===e||!Mn&&$n(e,t)?(e=nn(),tn=en=Jt=null,Hn=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return jn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Mr(r,"onBeforeInput")).length&&(a=new _n("onBeforeInput","beforeinput",null,n,a),i.push({event:a,listeners:r}),a.data=v))}Ar(i,t)}))}function Dr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Mr(e,t){for(var n=t+"Capture",r=[];null!==e;){var a=e,o=a.stateNode;5===a.tag&&null!==o&&(a=o,null!=(o=je(e,n))&&r.unshift(Dr(e,o,a)),null!=(o=je(e,t))&&r.push(Dr(e,o,a))),e=e.return}return r}function Br(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Fr(e,t,n,r,a){for(var o=t._reactName,i=[];null!==n&&n!==r;){var l=n,s=l.alternate,c=l.stateNode;if(null!==s&&s===r)break;5===l.tag&&null!==c&&(l=c,a?null!=(s=je(n,o))&&i.unshift(Dr(n,s,l)):a||null!=(s=je(n,o))&&i.push(Dr(n,s,l))),n=n.return}0!==i.length&&e.push({event:t,listeners:i})}function jr(){}var Ur=null,zr=null;function $r(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function qr(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Hr="function"==typeof setTimeout?setTimeout:void 0,Gr="function"==typeof clearTimeout?clearTimeout:void 0;function Zr(e){1===e.nodeType?e.textContent="":9===e.nodeType&&(null!=(e=e.body)&&(e.textContent=""))}function Vr(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function Wr(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var Kr=0;var Yr=Math.random().toString(36).slice(2),Qr="__reactFiber$"+Yr,Xr="__reactProps$"+Yr,Jr="__reactContainer$"+Yr,ea="__reactEvents$"+Yr;function ta(e){var t=e[Qr];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Jr]||n[Qr]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=Wr(e);null!==e;){if(n=e[Qr])return n;e=Wr(e)}return t}n=(e=n).parentNode}return null}function na(e){return!(e=e[Qr]||e[Jr])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function ra(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(i(33))}function aa(e){return e[Xr]||null}function oa(e){var t=e[ea];return void 0===t&&(t=e[ea]=new Set),t}var ia=[],la=-1;function sa(e){return{current:e}}function ca(e){0>la||(e.current=ia[la],ia[la]=null,la--)}function ua(e,t){la++,ia[la]=e.current,e.current=t}var da={},pa=sa(da),fa=sa(!1),ma=da;function ha(e,t){var n=e.type.contextTypes;if(!n)return da;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,o={};for(a in n)o[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function ga(e){return null!=(e=e.childContextTypes)}function ba(){ca(fa),ca(pa)}function va(e,t,n){if(pa.current!==da)throw Error(i(168));ua(pa,t),ua(fa,n)}function ya(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var o in r=r.getChildContext())if(!(o in e))throw Error(i(108,V(t)||"Unknown",o));return a({},n,r)}function wa(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||da,ma=pa.current,ua(pa,e),ua(fa,fa.current),!0}function ka(e,t,n){var r=e.stateNode;if(!r)throw Error(i(169));n?(e=ya(e,t,ma),r.__reactInternalMemoizedMergedChildContext=e,ca(fa),ca(pa),ua(pa,e)):ca(fa),ua(fa,n)}var _a=null,Sa=null,Ea=o.unstable_runWithPriority,xa=o.unstable_scheduleCallback,Ta=o.unstable_cancelCallback,Ca=o.unstable_shouldYield,Aa=o.unstable_requestPaint,La=o.unstable_now,Ra=o.unstable_getCurrentPriorityLevel,Pa=o.unstable_ImmediatePriority,Na=o.unstable_UserBlockingPriority,Oa=o.unstable_NormalPriority,Ia=o.unstable_LowPriority,Da=o.unstable_IdlePriority,Ma={},Ba=void 0!==Aa?Aa:function(){},Fa=null,ja=null,Ua=!1,za=La(),$a=1e4>za?La:function(){return La()-za};function qa(){switch(Ra()){case Pa:return 99;case Na:return 98;case Oa:return 97;case Ia:return 96;case Da:return 95;default:throw Error(i(332))}}function Ha(e){switch(e){case 99:return Pa;case 98:return Na;case 97:return Oa;case 96:return Ia;case 95:return Da;default:throw Error(i(332))}}function Ga(e,t){return e=Ha(e),Ea(e,t)}function Za(e,t,n){return e=Ha(e),xa(e,t,n)}function Va(){if(null!==ja){var e=ja;ja=null,Ta(e)}Wa()}function Wa(){if(!Ua&&null!==Fa){Ua=!0;var e=0;try{var t=Fa;Ga(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Fa=null}catch(n){throw null!==Fa&&(Fa=Fa.slice(e+1)),xa(Pa,Va),n}finally{Ua=!1}}}var Ka=k.ReactCurrentBatchConfig;function Ya(e,t){if(e&&e.defaultProps){for(var n in t=a({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var Qa=sa(null),Xa=null,Ja=null,eo=null;function to(){eo=Ja=Xa=null}function no(e){var t=Qa.current;ca(Qa),e.type._context._currentValue=t}function ro(e,t){for(;null!==e;){var n=e.alternate;if((e.childLanes&t)===t){if(null===n||(n.childLanes&t)===t)break;n.childLanes|=t}else e.childLanes|=t,null!==n&&(n.childLanes|=t);e=e.return}}function ao(e,t){Xa=e,eo=Ja=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(0!=(e.lanes&t)&&(Mi=!0),e.firstContext=null)}function oo(e,t){if(eo!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(eo=e,t=1073741823),t={context:e,observedBits:t,next:null},null===Ja){if(null===Xa)throw Error(i(308));Ja=t,Xa.dependencies={lanes:0,firstContext:t,responders:null}}else Ja=Ja.next=t;return e._currentValue}var io=!1;function lo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function so(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function co(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function uo(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function po(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var a=null,o=null;if(null!==(n=n.firstBaseUpdate)){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===o?a=o=i:o=o.next=i,n=n.next}while(null!==n);null===o?a=o=t:o=o.next=t}else a=o=t;return n={baseState:r.baseState,firstBaseUpdate:a,lastBaseUpdate:o,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function fo(e,t,n,r){var o=e.updateQueue;io=!1;var i=o.firstBaseUpdate,l=o.lastBaseUpdate,s=o.shared.pending;if(null!==s){o.shared.pending=null;var c=s,u=c.next;c.next=null,null===l?i=u:l.next=u,l=c;var d=e.alternate;if(null!==d){var p=(d=d.updateQueue).lastBaseUpdate;p!==l&&(null===p?d.firstBaseUpdate=u:p.next=u,d.lastBaseUpdate=c)}}if(null!==i){for(p=o.baseState,l=0,d=u=c=null;;){s=i.lane;var f=i.eventTime;if((r&s)===s){null!==d&&(d=d.next={eventTime:f,lane:0,tag:i.tag,payload:i.payload,callback:i.callback,next:null});e:{var m=e,h=i;switch(s=t,f=n,h.tag){case 1:if("function"==typeof(m=h.payload)){p=m.call(f,p,s);break e}p=m;break e;case 3:m.flags=-4097&m.flags|64;case 0:if(null==(s="function"==typeof(m=h.payload)?m.call(f,p,s):m))break e;p=a({},p,s);break e;case 2:io=!0}}null!==i.callback&&(e.flags|=32,null===(s=o.effects)?o.effects=[i]:s.push(i))}else f={eventTime:f,lane:s,tag:i.tag,payload:i.payload,callback:i.callback,next:null},null===d?(u=d=f,c=p):d=d.next=f,l|=s;if(null===(i=i.next)){if(null===(s=o.shared.pending))break;i=s.next,s.next=null,o.lastBaseUpdate=s,o.shared.pending=null}}null===d&&(c=p),o.baseState=c,o.firstBaseUpdate=u,o.lastBaseUpdate=d,zl|=l,e.lanes=l,e.memoizedState=p}}function mo(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=n,"function"!=typeof a)throw Error(i(191,a));a.call(r)}}}var ho=(new r.Component).refs;function go(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:a({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var bo={isMounted:function(e){return!!(e=e._reactInternals)&&Ke(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=ps(),a=fs(e),o=co(r,a);o.payload=t,null!=n&&(o.callback=n),uo(e,o),ms(e,a,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=ps(),a=fs(e),o=co(r,a);o.tag=1,o.payload=t,null!=n&&(o.callback=n),uo(e,o),ms(e,a,r)},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=ps(),r=fs(e),a=co(n,r);a.tag=2,null!=t&&(a.callback=t),uo(e,a),ms(e,r,n)}};function vo(e,t,n,r,a,o,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,o,i):!t.prototype||!t.prototype.isPureReactComponent||(!dr(n,r)||!dr(a,o))}function yo(e,t,n){var r=!1,a=da,o=t.contextType;return"object"==typeof o&&null!==o?o=oo(o):(a=ga(t)?ma:pa.current,o=(r=null!=(r=t.contextTypes))?ha(e,a):da),t=new t(n,o),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=bo,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=o),t}function wo(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&bo.enqueueReplaceState(t,t.state,null)}function ko(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=ho,lo(e);var o=t.contextType;"object"==typeof o&&null!==o?a.context=oo(o):(o=ga(t)?ma:pa.current,a.context=ha(e,o)),fo(e,n,a,r),a.state=e.memoizedState,"function"==typeof(o=t.getDerivedStateFromProps)&&(go(e,t,o,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&bo.enqueueReplaceState(a,a.state,null),fo(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.flags|=4)}var _o=Array.isArray;function So(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(i(309));var r=n.stateNode}if(!r)throw Error(i(147,e));var a=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===a?t.ref:(t=function(e){var t=r.refs;t===ho&&(t=r.refs={}),null===e?delete t[a]:t[a]=e},t._stringRef=a,t)}if("string"!=typeof e)throw Error(i(284));if(!n._owner)throw Error(i(290,e))}return e}function Eo(e,t){if("textarea"!==e.type)throw Error(i(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t))}function xo(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.flags=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Zs(e,t)).index=0,e.sibling=null,e}function o(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags=2,n):r:(t.flags=2,n):n}function l(t){return e&&null===t.alternate&&(t.flags=2),t}function s(e,t,n,r){return null===t||6!==t.tag?((t=Ys(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function c(e,t,n,r){return null!==t&&t.elementType===n.type?((r=a(t,n.props)).ref=So(e,t,n),r.return=e,r):((r=Vs(n.type,n.key,n.props,null,e.mode,r)).ref=So(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Qs(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,o){return null===t||7!==t.tag?((t=Ws(n,e.mode,r,o)).return=e,t):((t=a(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Ys(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case _:return(n=Vs(t.type,t.key,t.props,null,e.mode,n)).ref=So(e,null,t),n.return=e,n;case S:return(t=Qs(t,e.mode,n)).return=e,t}if(_o(t)||$(t))return(t=Ws(t,e.mode,n,null)).return=e,t;Eo(e,t)}return null}function f(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==a?null:s(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case _:return n.key===a?n.type===E?d(e,t,n.props.children,r,a):c(e,t,n,r):null;case S:return n.key===a?u(e,t,n,r):null}if(_o(n)||$(n))return null!==a?null:d(e,t,n,r,null);Eo(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r||"number"==typeof r)return s(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case _:return e=e.get(null===r.key?n:r.key)||null,r.type===E?d(t,e,r.props.children,a,r.key):c(t,e,r,a);case S:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a)}if(_o(r)||$(r))return d(t,e=e.get(n)||null,r,a,null);Eo(t,r)}return null}function h(a,i,l,s){for(var c=null,u=null,d=i,h=i=0,g=null;null!==d&&h<l.length;h++){d.index>h?(g=d,d=null):g=d.sibling;var b=f(a,d,l[h],s);if(null===b){null===d&&(d=g);break}e&&d&&null===b.alternate&&t(a,d),i=o(b,i,h),null===u?c=b:u.sibling=b,u=b,d=g}if(h===l.length)return n(a,d),c;if(null===d){for(;h<l.length;h++)null!==(d=p(a,l[h],s))&&(i=o(d,i,h),null===u?c=d:u.sibling=d,u=d);return c}for(d=r(a,d);h<l.length;h++)null!==(g=m(d,a,h,l[h],s))&&(e&&null!==g.alternate&&d.delete(null===g.key?h:g.key),i=o(g,i,h),null===u?c=g:u.sibling=g,u=g);return e&&d.forEach((function(e){return t(a,e)})),c}function g(a,l,s,c){var u=$(s);if("function"!=typeof u)throw Error(i(150));if(null==(s=u.call(s)))throw Error(i(151));for(var d=u=null,h=l,g=l=0,b=null,v=s.next();null!==h&&!v.done;g++,v=s.next()){h.index>g?(b=h,h=null):b=h.sibling;var y=f(a,h,v.value,c);if(null===y){null===h&&(h=b);break}e&&h&&null===y.alternate&&t(a,h),l=o(y,l,g),null===d?u=y:d.sibling=y,d=y,h=b}if(v.done)return n(a,h),u;if(null===h){for(;!v.done;g++,v=s.next())null!==(v=p(a,v.value,c))&&(l=o(v,l,g),null===d?u=v:d.sibling=v,d=v);return u}for(h=r(a,h);!v.done;g++,v=s.next())null!==(v=m(h,a,g,v.value,c))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),l=o(v,l,g),null===d?u=v:d.sibling=v,d=v);return e&&h.forEach((function(e){return t(a,e)})),u}return function(e,r,o,s){var c="object"==typeof o&&null!==o&&o.type===E&&null===o.key;c&&(o=o.props.children);var u="object"==typeof o&&null!==o;if(u)switch(o.$$typeof){case _:e:{for(u=o.key,c=r;null!==c;){if(c.key===u){if(7===c.tag){if(o.type===E){n(e,c.sibling),(r=a(c,o.props.children)).return=e,e=r;break e}}else if(c.elementType===o.type){n(e,c.sibling),(r=a(c,o.props)).ref=So(e,c,o),r.return=e,e=r;break e}n(e,c);break}t(e,c),c=c.sibling}o.type===E?((r=Ws(o.props.children,e.mode,s,o.key)).return=e,e=r):((s=Vs(o.type,o.key,o.props,null,e.mode,s)).ref=So(e,r,o),s.return=e,e=s)}return l(e);case S:e:{for(c=o.key;null!==r;){if(r.key===c){if(4===r.tag&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),(r=a(r,o.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=Qs(o,e.mode,s)).return=e,e=r}return l(e)}if("string"==typeof o||"number"==typeof o)return o=""+o,null!==r&&6===r.tag?(n(e,r.sibling),(r=a(r,o)).return=e,e=r):(n(e,r),(r=Ys(o,e.mode,s)).return=e,e=r),l(e);if(_o(o))return h(e,r,o,s);if($(o))return g(e,r,o,s);if(u&&Eo(e,o),void 0===o&&!c)switch(e.tag){case 1:case 22:case 0:case 11:case 15:throw Error(i(152,V(e.type)||"Component"))}return n(e,r)}}var To=xo(!0),Co=xo(!1),Ao={},Lo=sa(Ao),Ro=sa(Ao),Po=sa(Ao);function No(e){if(e===Ao)throw Error(i(174));return e}function Oo(e,t){switch(ua(Po,t),ua(Ro,e),ua(Lo,Ao),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:fe(null,"");break;default:t=fe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}ca(Lo),ua(Lo,t)}function Io(){ca(Lo),ca(Ro),ca(Po)}function Do(e){No(Po.current);var t=No(Lo.current),n=fe(t,e.type);t!==n&&(ua(Ro,e),ua(Lo,n))}function Mo(e){Ro.current===e&&(ca(Lo),ca(Ro))}var Bo=sa(0);function Fo(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.flags))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var jo=null,Uo=null,zo=!1;function $o(e,t){var n=Hs(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function qo(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Ho(e){if(zo){var t=Uo;if(t){var n=t;if(!qo(e,t)){if(!(t=Vr(n.nextSibling))||!qo(e,t))return e.flags=-1025&e.flags|2,zo=!1,void(jo=e);$o(jo,n)}jo=e,Uo=Vr(t.firstChild)}else e.flags=-1025&e.flags|2,zo=!1,jo=e}}function Go(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;jo=e}function Zo(e){if(e!==jo)return!1;if(!zo)return Go(e),zo=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!qr(t,e.memoizedProps))for(t=Uo;t;)$o(e,t),t=Vr(t.nextSibling);if(Go(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(i(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){Uo=Vr(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}Uo=null}}else Uo=jo?Vr(e.stateNode.nextSibling):null;return!0}function Vo(){Uo=jo=null,zo=!1}var Wo=[];function Ko(){for(var e=0;e<Wo.length;e++)Wo[e]._workInProgressVersionPrimary=null;Wo.length=0}var Yo=k.ReactCurrentDispatcher,Qo=k.ReactCurrentBatchConfig,Xo=0,Jo=null,ei=null,ti=null,ni=!1,ri=!1;function ai(){throw Error(i(321))}function oi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!cr(e[n],t[n]))return!1;return!0}function ii(e,t,n,r,a,o){if(Xo=o,Jo=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,Yo.current=null===e||null===e.memoizedState?Ni:Oi,e=n(r,a),ri){o=0;do{if(ri=!1,!(25>o))throw Error(i(301));o+=1,ti=ei=null,t.updateQueue=null,Yo.current=Ii,e=n(r,a)}while(ri)}if(Yo.current=Pi,t=null!==ei&&null!==ei.next,Xo=0,ti=ei=Jo=null,ni=!1,t)throw Error(i(300));return e}function li(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===ti?Jo.memoizedState=ti=e:ti=ti.next=e,ti}function si(){if(null===ei){var e=Jo.alternate;e=null!==e?e.memoizedState:null}else e=ei.next;var t=null===ti?Jo.memoizedState:ti.next;if(null!==t)ti=t,ei=e;else{if(null===e)throw Error(i(310));e={memoizedState:(ei=e).memoizedState,baseState:ei.baseState,baseQueue:ei.baseQueue,queue:ei.queue,next:null},null===ti?Jo.memoizedState=ti=e:ti=ti.next=e}return ti}function ci(e,t){return"function"==typeof t?t(e):t}function ui(e){var t=si(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=ei,a=r.baseQueue,o=n.pending;if(null!==o){if(null!==a){var l=a.next;a.next=o.next,o.next=l}r.baseQueue=a=o,n.pending=null}if(null!==a){a=a.next,r=r.baseState;var s=l=o=null,c=a;do{var u=c.lane;if((Xo&u)===u)null!==s&&(s=s.next={lane:0,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null}),r=c.eagerReducer===e?c.eagerState:e(r,c.action);else{var d={lane:u,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null};null===s?(l=s=d,o=r):s=s.next=d,Jo.lanes|=u,zl|=u}c=c.next}while(null!==c&&c!==a);null===s?o=r:s.next=l,cr(r,t.memoizedState)||(Mi=!0),t.memoizedState=r,t.baseState=o,t.baseQueue=s,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function di(e){var t=si(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,o=t.memoizedState;if(null!==a){n.pending=null;var l=a=a.next;do{o=e(o,l.action),l=l.next}while(l!==a);cr(o,t.memoizedState)||(Mi=!0),t.memoizedState=o,null===t.baseQueue&&(t.baseState=o),n.lastRenderedState=o}return[o,r]}function pi(e,t,n){var r=t._getVersion;r=r(t._source);var a=t._workInProgressVersionPrimary;if(null!==a?e=a===r:(e=e.mutableReadLanes,(e=(Xo&e)===e)&&(t._workInProgressVersionPrimary=r,Wo.push(t))),e)return n(t._source);throw Wo.push(t),Error(i(350))}function fi(e,t,n,r){var a=Ol;if(null===a)throw Error(i(349));var o=t._getVersion,l=o(t._source),s=Yo.current,c=s.useState((function(){return pi(a,t,n)})),u=c[1],d=c[0];c=ti;var p=e.memoizedState,f=p.refs,m=f.getSnapshot,h=p.source;p=p.subscribe;var g=Jo;return e.memoizedState={refs:f,source:t,subscribe:r},s.useEffect((function(){f.getSnapshot=n,f.setSnapshot=u;var e=o(t._source);if(!cr(l,e)){e=n(t._source),cr(d,e)||(u(e),e=fs(g),a.mutableReadLanes|=e&a.pendingLanes),e=a.mutableReadLanes,a.entangledLanes|=e;for(var r=a.entanglements,i=e;0<i;){var s=31-qt(i),c=1<<s;r[s]|=e,i&=~c}}}),[n,t,r]),s.useEffect((function(){return r(t._source,(function(){var e=f.getSnapshot,n=f.setSnapshot;try{n(e(t._source));var r=fs(g);a.mutableReadLanes|=r&a.pendingLanes}catch(o){n((function(){throw o}))}}))}),[t,r]),cr(m,n)&&cr(h,t)&&cr(p,r)||((e={pending:null,dispatch:null,lastRenderedReducer:ci,lastRenderedState:d}).dispatch=u=Ri.bind(null,Jo,e),c.queue=e,c.baseQueue=null,d=pi(a,t,n),c.memoizedState=c.baseState=d),d}function mi(e,t,n){return fi(si(),e,t,n)}function hi(e){var t=li();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:ci,lastRenderedState:e}).dispatch=Ri.bind(null,Jo,e),[t.memoizedState,e]}function gi(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=Jo.updateQueue)?(t={lastEffect:null},Jo.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function bi(e){return e={current:e},li().memoizedState=e}function vi(){return si().memoizedState}function yi(e,t,n,r){var a=li();Jo.flags|=e,a.memoizedState=gi(1|t,n,void 0,void 0===r?null:r)}function wi(e,t,n,r){var a=si();r=void 0===r?null:r;var o=void 0;if(null!==ei){var i=ei.memoizedState;if(o=i.destroy,null!==r&&oi(r,i.deps))return void gi(t,n,o,r)}Jo.flags|=e,a.memoizedState=gi(1|t,n,o,r)}function ki(e,t){return yi(516,4,e,t)}function _i(e,t){return wi(516,4,e,t)}function Si(e,t){return wi(4,2,e,t)}function Ei(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function xi(e,t,n){return n=null!=n?n.concat([e]):null,wi(4,2,Ei.bind(null,t,e),n)}function Ti(){}function Ci(e,t){var n=si();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&oi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Ai(e,t){var n=si();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&oi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Li(e,t){var n=qa();Ga(98>n?98:n,(function(){e(!0)})),Ga(97<n?97:n,(function(){var n=Qo.transition;Qo.transition=1;try{e(!1),t()}finally{Qo.transition=n}}))}function Ri(e,t,n){var r=ps(),a=fs(e),o={lane:a,action:n,eagerReducer:null,eagerState:null,next:null},i=t.pending;if(null===i?o.next=o:(o.next=i.next,i.next=o),t.pending=o,i=e.alternate,e===Jo||null!==i&&i===Jo)ri=ni=!0;else{if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=t.lastRenderedReducer))try{var l=t.lastRenderedState,s=i(l,n);if(o.eagerReducer=i,o.eagerState=s,cr(s,l))return}catch(c){}ms(e,a,r)}}var Pi={readContext:oo,useCallback:ai,useContext:ai,useEffect:ai,useImperativeHandle:ai,useLayoutEffect:ai,useMemo:ai,useReducer:ai,useRef:ai,useState:ai,useDebugValue:ai,useDeferredValue:ai,useTransition:ai,useMutableSource:ai,useOpaqueIdentifier:ai,unstable_isNewReconciler:!1},Ni={readContext:oo,useCallback:function(e,t){return li().memoizedState=[e,void 0===t?null:t],e},useContext:oo,useEffect:ki,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,yi(4,2,Ei.bind(null,t,e),n)},useLayoutEffect:function(e,t){return yi(4,2,e,t)},useMemo:function(e,t){var n=li();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=li();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=Ri.bind(null,Jo,e),[r.memoizedState,e]},useRef:bi,useState:hi,useDebugValue:Ti,useDeferredValue:function(e){var t=hi(e),n=t[0],r=t[1];return ki((function(){var t=Qo.transition;Qo.transition=1;try{r(e)}finally{Qo.transition=t}}),[e]),n},useTransition:function(){var e=hi(!1),t=e[0];return bi(e=Li.bind(null,e[1])),[e,t]},useMutableSource:function(e,t,n){var r=li();return r.memoizedState={refs:{getSnapshot:t,setSnapshot:null},source:e,subscribe:n},fi(r,e,t,n)},useOpaqueIdentifier:function(){if(zo){var e=!1,t=function(e){return{$$typeof:D,toString:e,valueOf:e}}((function(){throw e||(e=!0,n("r:"+(Kr++).toString(36))),Error(i(355))})),n=hi(t)[1];return 0==(2&Jo.mode)&&(Jo.flags|=516,gi(5,(function(){n("r:"+(Kr++).toString(36))}),void 0,null)),t}return hi(t="r:"+(Kr++).toString(36)),t},unstable_isNewReconciler:!1},Oi={readContext:oo,useCallback:Ci,useContext:oo,useEffect:_i,useImperativeHandle:xi,useLayoutEffect:Si,useMemo:Ai,useReducer:ui,useRef:vi,useState:function(){return ui(ci)},useDebugValue:Ti,useDeferredValue:function(e){var t=ui(ci),n=t[0],r=t[1];return _i((function(){var t=Qo.transition;Qo.transition=1;try{r(e)}finally{Qo.transition=t}}),[e]),n},useTransition:function(){var e=ui(ci)[0];return[vi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return ui(ci)[0]},unstable_isNewReconciler:!1},Ii={readContext:oo,useCallback:Ci,useContext:oo,useEffect:_i,useImperativeHandle:xi,useLayoutEffect:Si,useMemo:Ai,useReducer:di,useRef:vi,useState:function(){return di(ci)},useDebugValue:Ti,useDeferredValue:function(e){var t=di(ci),n=t[0],r=t[1];return _i((function(){var t=Qo.transition;Qo.transition=1;try{r(e)}finally{Qo.transition=t}}),[e]),n},useTransition:function(){var e=di(ci)[0];return[vi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return di(ci)[0]},unstable_isNewReconciler:!1},Di=k.ReactCurrentOwner,Mi=!1;function Bi(e,t,n,r){t.child=null===e?Co(t,null,n,r):To(t,e.child,n,r)}function Fi(e,t,n,r,a){n=n.render;var o=t.ref;return ao(t,a),r=ii(e,t,n,r,o,a),null===e||Mi?(t.flags|=1,Bi(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,ol(e,t,a))}function ji(e,t,n,r,a,o){if(null===e){var i=n.type;return"function"!=typeof i||Gs(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Vs(n.type,null,r,t,t.mode,o)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=i,Ui(e,t,i,r,a,o))}return i=e.child,0==(a&o)&&(a=i.memoizedProps,(n=null!==(n=n.compare)?n:dr)(a,r)&&e.ref===t.ref)?ol(e,t,o):(t.flags|=1,(e=Zs(i,r)).ref=t.ref,e.return=t,t.child=e)}function Ui(e,t,n,r,a,o){if(null!==e&&dr(e.memoizedProps,r)&&e.ref===t.ref){if(Mi=!1,0==(o&a))return t.lanes=e.lanes,ol(e,t,o);0!=(16384&e.flags)&&(Mi=!0)}return qi(e,t,n,r,o)}function zi(e,t,n){var r=t.pendingProps,a=r.children,o=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(4&t.mode))t.memoizedState={baseLanes:0},_s(t,n);else{if(0==(1073741824&n))return e=null!==o?o.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e},_s(t,e),null;t.memoizedState={baseLanes:0},_s(t,null!==o?o.baseLanes:n)}else null!==o?(r=o.baseLanes|n,t.memoizedState=null):r=n,_s(t,r);return Bi(e,t,a,n),t.child}function $i(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=128)}function qi(e,t,n,r,a){var o=ga(n)?ma:pa.current;return o=ha(t,o),ao(t,a),n=ii(e,t,n,r,o,a),null===e||Mi?(t.flags|=1,Bi(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,ol(e,t,a))}function Hi(e,t,n,r,a){if(ga(n)){var o=!0;wa(t)}else o=!1;if(ao(t,a),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),yo(t,n,r),ko(t,n,r,a),r=!0;else if(null===e){var i=t.stateNode,l=t.memoizedProps;i.props=l;var s=i.context,c=n.contextType;"object"==typeof c&&null!==c?c=oo(c):c=ha(t,c=ga(n)?ma:pa.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==r||s!==c)&&wo(t,i,r,c),io=!1;var p=t.memoizedState;i.state=p,fo(t,r,i,a),s=t.memoizedState,l!==r||p!==s||fa.current||io?("function"==typeof u&&(go(t,n,u,r),s=t.memoizedState),(l=io||vo(t,n,l,r,p,s,c))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(t.flags|=4)):("function"==typeof i.componentDidMount&&(t.flags|=4),t.memoizedProps=r,t.memoizedState=s),i.props=r,i.state=s,i.context=c,r=l):("function"==typeof i.componentDidMount&&(t.flags|=4),r=!1)}else{i=t.stateNode,so(e,t),l=t.memoizedProps,c=t.type===t.elementType?l:Ya(t.type,l),i.props=c,d=t.pendingProps,p=i.context,"object"==typeof(s=n.contextType)&&null!==s?s=oo(s):s=ha(t,s=ga(n)?ma:pa.current);var f=n.getDerivedStateFromProps;(u="function"==typeof f||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==d||p!==s)&&wo(t,i,r,s),io=!1,p=t.memoizedState,i.state=p,fo(t,r,i,a);var m=t.memoizedState;l!==d||p!==m||fa.current||io?("function"==typeof f&&(go(t,n,f,r),m=t.memoizedState),(c=io||vo(t,n,c,r,p,m,s))?(u||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,m,s),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,m,s)),"function"==typeof i.componentDidUpdate&&(t.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(t.flags|=256)):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),t.memoizedProps=r,t.memoizedState=m),i.props=r,i.state=m,i.context=s,r=c):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),r=!1)}return Gi(e,t,n,r,o,a)}function Gi(e,t,n,r,a,o){$i(e,t);var i=0!=(64&t.flags);if(!r&&!i)return a&&ka(t,n,!1),ol(e,t,o);r=t.stateNode,Di.current=t;var l=i&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&i?(t.child=To(t,e.child,null,o),t.child=To(t,null,l,o)):Bi(e,t,l,o),t.memoizedState=r.state,a&&ka(t,n,!0),t.child}function Zi(e){var t=e.stateNode;t.pendingContext?va(0,t.pendingContext,t.pendingContext!==t.context):t.context&&va(0,t.context,!1),Oo(e,t.containerInfo)}var Vi,Wi,Ki,Yi,Qi={dehydrated:null,retryLane:0};function Xi(e,t,n){var r,a=t.pendingProps,o=Bo.current,i=!1;return(r=0!=(64&t.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&o)),r?(i=!0,t.flags&=-65):null!==e&&null===e.memoizedState||void 0===a.fallback||!0===a.unstable_avoidThisFallback||(o|=1),ua(Bo,1&o),null===e?(void 0!==a.fallback&&Ho(t),e=a.children,o=a.fallback,i?(e=Ji(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Qi,e):"number"==typeof a.unstable_expectedLoadTime?(e=Ji(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Qi,t.lanes=33554432,e):((n=Ks({mode:"visible",children:e},t.mode,n,null)).return=t,t.child=n)):(e.memoizedState,i?(a=tl(e,t,a.children,a.fallback,n),i=t.child,o=e.child.memoizedState,i.memoizedState=null===o?{baseLanes:n}:{baseLanes:o.baseLanes|n},i.childLanes=e.childLanes&~n,t.memoizedState=Qi,a):(n=el(e,t,a.children,n),t.memoizedState=null,n))}function Ji(e,t,n,r){var a=e.mode,o=e.child;return t={mode:"hidden",children:t},0==(2&a)&&null!==o?(o.childLanes=0,o.pendingProps=t):o=Ks(t,a,0,null),n=Ws(n,a,r,null),o.return=e,n.return=e,o.sibling=n,e.child=o,n}function el(e,t,n,r){var a=e.child;return e=a.sibling,n=Zs(a,{mode:"visible",children:n}),0==(2&t.mode)&&(n.lanes=r),n.return=t,n.sibling=null,null!==e&&(e.nextEffect=null,e.flags=8,t.firstEffect=t.lastEffect=e),t.child=n}function tl(e,t,n,r,a){var o=t.mode,i=e.child;e=i.sibling;var l={mode:"hidden",children:n};return 0==(2&o)&&t.child!==i?((n=t.child).childLanes=0,n.pendingProps=l,null!==(i=n.lastEffect)?(t.firstEffect=n.firstEffect,t.lastEffect=i,i.nextEffect=null):t.firstEffect=t.lastEffect=null):n=Zs(i,l),null!==e?r=Zs(e,r):(r=Ws(r,o,a,null)).flags|=2,r.return=t,n.return=t,n.sibling=r,t.child=n,r}function nl(e,t){e.lanes|=t;var n=e.alternate;null!==n&&(n.lanes|=t),ro(e.return,t)}function rl(e,t,n,r,a,o){var i=e.memoizedState;null===i?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a,lastEffect:o}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=r,i.tail=n,i.tailMode=a,i.lastEffect=o)}function al(e,t,n){var r=t.pendingProps,a=r.revealOrder,o=r.tail;if(Bi(e,t,r.children,n),0!=(2&(r=Bo.current)))r=1&r|2,t.flags|=64;else{if(null!==e&&0!=(64&e.flags))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&nl(e,n);else if(19===e.tag)nl(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ua(Bo,r),0==(2&t.mode))t.memoizedState=null;else switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===Fo(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),rl(t,!1,a,n,o,t.lastEffect);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===Fo(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}rl(t,!0,n,null,o,t.lastEffect);break;case"together":rl(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}return t.child}function ol(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),zl|=t.lanes,0!=(n&t.childLanes)){if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Zs(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Zs(e,e.pendingProps)).return=t;n.sibling=null}return t.child}return null}function il(e,t){if(!zo)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ll(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return ga(t.type)&&ba(),null;case 3:return Io(),ca(fa),ca(pa),Ko(),(r=t.stateNode).pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(Zo(t)?t.flags|=4:r.hydrate||(t.flags|=256)),Wi(t),null;case 5:Mo(t);var o=No(Po.current);if(n=t.type,null!==e&&null!=t.stateNode)Ki(e,t,n,r,o),e.ref!==t.ref&&(t.flags|=128);else{if(!r){if(null===t.stateNode)throw Error(i(166));return null}if(e=No(Lo.current),Zo(t)){r=t.stateNode,n=t.type;var l=t.memoizedProps;switch(r[Qr]=t,r[Xr]=l,n){case"dialog":Lr("cancel",r),Lr("close",r);break;case"iframe":case"object":case"embed":Lr("load",r);break;case"video":case"audio":for(e=0;e<xr.length;e++)Lr(xr[e],r);break;case"source":Lr("error",r);break;case"img":case"image":case"link":Lr("error",r),Lr("load",r);break;case"details":Lr("toggle",r);break;case"input":ee(r,l),Lr("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!l.multiple},Lr("invalid",r);break;case"textarea":se(r,l),Lr("invalid",r)}for(var c in Se(n,l),e=null,l)l.hasOwnProperty(c)&&(o=l[c],"children"===c?"string"==typeof o?r.textContent!==o&&(e=["children",o]):"number"==typeof o&&r.textContent!==""+o&&(e=["children",""+o]):s.hasOwnProperty(c)&&null!=o&&"onScroll"===c&&Lr("scroll",r));switch(n){case"input":Y(r),re(r,l,!0);break;case"textarea":Y(r),ue(r);break;case"select":case"option":break;default:"function"==typeof l.onClick&&(r.onclick=jr)}r=e,t.updateQueue=r,null!==r&&(t.flags|=4)}else{switch(c=9===o.nodeType?o:o.ownerDocument,e===de.html&&(e=pe(n)),e===de.html?"script"===n?((e=c.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=c.createElement(n,{is:r.is}):(e=c.createElement(n),"select"===n&&(c=e,r.multiple?c.multiple=!0:r.size&&(c.size=r.size))):e=c.createElementNS(e,n),e[Qr]=t,e[Xr]=r,Vi(e,t,!1,!1),t.stateNode=e,c=Ee(n,r),n){case"dialog":Lr("cancel",e),Lr("close",e),o=r;break;case"iframe":case"object":case"embed":Lr("load",e),o=r;break;case"video":case"audio":for(o=0;o<xr.length;o++)Lr(xr[o],e);o=r;break;case"source":Lr("error",e),o=r;break;case"img":case"image":case"link":Lr("error",e),Lr("load",e),o=r;break;case"details":Lr("toggle",e),o=r;break;case"input":ee(e,r),o=J(e,r),Lr("invalid",e);break;case"option":o=oe(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},o=a({},r,{value:void 0}),Lr("invalid",e);break;case"textarea":se(e,r),o=le(e,r),Lr("invalid",e);break;default:o=r}Se(n,o);var u=o;for(l in u)if(u.hasOwnProperty(l)){var d=u[l];"style"===l?ke(e,d):"dangerouslySetInnerHTML"===l?null!=(d=d?d.__html:void 0)&&ge(e,d):"children"===l?"string"==typeof d?("textarea"!==n||""!==d)&&be(e,d):"number"==typeof d&&be(e,""+d):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(s.hasOwnProperty(l)?null!=d&&"onScroll"===l&&Lr("scroll",e):null!=d&&w(e,l,d,c))}switch(n){case"input":Y(e),re(e,r,!1);break;case"textarea":Y(e),ue(e);break;case"option":null!=r.value&&e.setAttribute("value",""+W(r.value));break;case"select":e.multiple=!!r.multiple,null!=(l=r.value)?ie(e,!!r.multiple,l,!1):null!=r.defaultValue&&ie(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof o.onClick&&(e.onclick=jr)}$r(n,r)&&(t.flags|=4)}null!==t.ref&&(t.flags|=128)}return null;case 6:if(e&&null!=t.stateNode)Yi(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(i(166));n=No(Po.current),No(Lo.current),Zo(t)?(r=t.stateNode,n=t.memoizedProps,r[Qr]=t,r.nodeValue!==n&&(t.flags|=4)):((r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[Qr]=t,t.stateNode=r)}return null;case 13:return ca(Bo),r=t.memoizedState,0!=(64&t.flags)?(t.lanes=n,t):(r=null!==r,n=!1,null===e?void 0!==t.memoizedProps.fallback&&Zo(t):n=null!==e.memoizedState,r&&!n&&0!=(2&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&Bo.current)?0===Fl&&(Fl=3):(0!==Fl&&3!==Fl||(Fl=4),null===Ol||0==(134217727&zl)&&0==(134217727&$l)||vs(Ol,Dl))),(r||n)&&(t.flags|=4),null);case 4:return Io(),Wi(t),null===e&&Pr(t.stateNode.containerInfo),null;case 10:return no(t),null;case 19:if(ca(Bo),null===(r=t.memoizedState))return null;if(l=0!=(64&t.flags),null===(c=r.rendering))if(l)il(r,!1);else{if(0!==Fl||null!==e&&0!=(64&e.flags))for(e=t.child;null!==e;){if(null!==(c=Fo(e))){for(t.flags|=64,il(r,!1),null!==(l=c.updateQueue)&&(t.updateQueue=l,t.flags|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=n,n=t.child;null!==n;)e=r,(l=n).flags&=2,l.nextEffect=null,l.firstEffect=null,l.lastEffect=null,null===(c=l.alternate)?(l.childLanes=0,l.lanes=e,l.child=null,l.memoizedProps=null,l.memoizedState=null,l.updateQueue=null,l.dependencies=null,l.stateNode=null):(l.childLanes=c.childLanes,l.lanes=c.lanes,l.child=c.child,l.memoizedProps=c.memoizedProps,l.memoizedState=c.memoizedState,l.updateQueue=c.updateQueue,l.type=c.type,e=c.dependencies,l.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return ua(Bo,1&Bo.current|2),t.child}e=e.sibling}null!==r.tail&&$a()>Zl&&(t.flags|=64,l=!0,il(r,!1),t.lanes=33554432)}else{if(!l)if(null!==(e=Fo(c))){if(t.flags|=64,l=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),il(r,!0),null===r.tail&&"hidden"===r.tailMode&&!c.alternate&&!zo)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*$a()-r.renderingStartTime>Zl&&1073741824!==n&&(t.flags|=64,l=!0,il(r,!1),t.lanes=33554432);r.isBackwards?(c.sibling=t.child,t.child=c):(null!==(n=r.last)?n.sibling=c:t.child=c,r.last=c)}return null!==r.tail?(n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=$a(),n.sibling=null,t=Bo.current,ua(Bo,l?1&t|2:1&t),n):null;case 23:case 24:return Ss(),null!==e&&null!==e.memoizedState!=(null!==t.memoizedState)&&"unstable-defer-without-hiding"!==r.mode&&(t.flags|=4),null}throw Error(i(156,t.tag))}function sl(e){switch(e.tag){case 1:ga(e.type)&&ba();var t=e.flags;return 4096&t?(e.flags=-4097&t|64,e):null;case 3:if(Io(),ca(fa),ca(pa),Ko(),0!=(64&(t=e.flags)))throw Error(i(285));return e.flags=-4097&t|64,e;case 5:return Mo(e),null;case 13:return ca(Bo),4096&(t=e.flags)?(e.flags=-4097&t|64,e):null;case 19:return ca(Bo),null;case 4:return Io(),null;case 10:return no(e),null;case 23:case 24:return Ss(),null;default:return null}}function cl(e,t){try{var n="",r=t;do{n+=Z(r),r=r.return}while(r);var a=n}catch(o){a="\nError generating stack: "+o.message+"\n"+o.stack}return{value:e,source:t,stack:a}}function ul(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}Vi=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Wi=function(){},Ki=function(e,t,n,r){var o=e.memoizedProps;if(o!==r){e=t.stateNode,No(Lo.current);var i,l=null;switch(n){case"input":o=J(e,o),r=J(e,r),l=[];break;case"option":o=oe(e,o),r=oe(e,r),l=[];break;case"select":o=a({},o,{value:void 0}),r=a({},r,{value:void 0}),l=[];break;case"textarea":o=le(e,o),r=le(e,r),l=[];break;default:"function"!=typeof o.onClick&&"function"==typeof r.onClick&&(e.onclick=jr)}for(d in Se(n,r),n=null,o)if(!r.hasOwnProperty(d)&&o.hasOwnProperty(d)&&null!=o[d])if("style"===d){var c=o[d];for(i in c)c.hasOwnProperty(i)&&(n||(n={}),n[i]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(s.hasOwnProperty(d)?l||(l=[]):(l=l||[]).push(d,null));for(d in r){var u=r[d];if(c=null!=o?o[d]:void 0,r.hasOwnProperty(d)&&u!==c&&(null!=u||null!=c))if("style"===d)if(c){for(i in c)!c.hasOwnProperty(i)||u&&u.hasOwnProperty(i)||(n||(n={}),n[i]="");for(i in u)u.hasOwnProperty(i)&&c[i]!==u[i]&&(n||(n={}),n[i]=u[i])}else n||(l||(l=[]),l.push(d,n)),n=u;else"dangerouslySetInnerHTML"===d?(u=u?u.__html:void 0,c=c?c.__html:void 0,null!=u&&c!==u&&(l=l||[]).push(d,u)):"children"===d?"string"!=typeof u&&"number"!=typeof u||(l=l||[]).push(d,""+u):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(s.hasOwnProperty(d)?(null!=u&&"onScroll"===d&&Lr("scroll",e),l||c===u||(l=[])):"object"==typeof u&&null!==u&&u.$$typeof===D?u.toString():(l=l||[]).push(d,u))}n&&(l=l||[]).push("style",n);var d=l;(t.updateQueue=d)&&(t.flags|=4)}},Yi=function(e,t,n,r){n!==r&&(t.flags|=4)};var dl="function"==typeof WeakMap?WeakMap:Map;function pl(e,t,n){(n=co(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Yl||(Yl=!0,Ql=r),ul(0,t)},n}function fl(e,t,n){(n=co(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return ul(0,t),r(a)}}var o=e.stateNode;return null!==o&&"function"==typeof o.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===Xl?Xl=new Set([this]):Xl.add(this),ul(0,t));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}var ml="function"==typeof WeakSet?WeakSet:Set;function hl(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){Us(e,n)}else t.current=null}function gl(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 5:case 6:case 4:case 17:return;case 1:if(256&t.flags&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:Ya(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return;case 3:return void(256&t.flags&&Zr(t.stateNode.containerInfo))}throw Error(i(163))}function bl(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{if(3==(3&e.tag)){var r=e.create;e.destroy=r()}e=e.next}while(e!==t)}if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{var a=e;r=a.next,0!=(4&(a=a.tag))&&0!=(1&a)&&(Bs(n,e),Ms(n,e)),e=r}while(e!==t)}return;case 1:return e=n.stateNode,4&n.flags&&(null===t?e.componentDidMount():(r=n.elementType===n.type?t.memoizedProps:Ya(n.type,t.memoizedProps),e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate))),void(null!==(t=n.updateQueue)&&mo(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}mo(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.flags&&$r(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:case 23:case 24:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&kt(n)))))}throw Error(i(163))}function vl(e,t){for(var n=e;;){if(5===n.tag){var r=n.stateNode;if(t)"function"==typeof(r=r.style).setProperty?r.setProperty("display","none","important"):r.display="none";else{r=n.stateNode;var a=n.memoizedProps.style;a=null!=a&&a.hasOwnProperty("display")?a.display:null,r.style.display=we("display",a)}}else if(6===n.tag)n.stateNode.nodeValue=t?"":n.memoizedProps;else if((23!==n.tag&&24!==n.tag||null===n.memoizedState||n===e)&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return;n=n.return}n.sibling.return=n.return,n=n.sibling}}function yl(e,t){if(Sa&&"function"==typeof Sa.onCommitFiberUnmount)try{Sa.onCommitFiberUnmount(_a,t)}catch(o){}switch(t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var n=e=e.next;do{var r=n,a=r.destroy;if(r=r.tag,void 0!==a)if(0!=(4&r))Bs(t,n);else{r=t;try{a()}catch(o){Us(r,o)}}n=n.next}while(n!==e)}break;case 1:if(hl(t),"function"==typeof(e=t.stateNode).componentWillUnmount)try{e.props=t.memoizedProps,e.state=t.memoizedState,e.componentWillUnmount()}catch(o){Us(t,o)}break;case 5:hl(t);break;case 4:xl(e,t)}}function wl(e){e.alternate=null,e.child=null,e.dependencies=null,e.firstEffect=null,e.lastEffect=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.return=null,e.updateQueue=null}function kl(e){return 5===e.tag||3===e.tag||4===e.tag}function _l(e){e:{for(var t=e.return;null!==t;){if(kl(t))break e;t=t.return}throw Error(i(160))}var n=t;switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(i(161))}16&n.flags&&(be(t,""),n.flags&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||kl(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.flags)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.flags)){n=n.stateNode;break e}}r?Sl(e,n,t):El(e,n,t)}function Sl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=jr));else if(4!==r&&null!==(e=e.child))for(Sl(e,t,n),e=e.sibling;null!==e;)Sl(e,t,n),e=e.sibling}function El(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(El(e,t,n),e=e.sibling;null!==e;)El(e,t,n),e=e.sibling}function xl(e,t){for(var n,r,a=t,o=!1;;){if(!o){o=a.return;e:for(;;){if(null===o)throw Error(i(160));switch(n=o.stateNode,o.tag){case 5:r=!1;break e;case 3:case 4:n=n.containerInfo,r=!0;break e}o=o.return}o=!0}if(5===a.tag||6===a.tag){e:for(var l=e,s=a,c=s;;)if(yl(l,c),null!==c.child&&4!==c.tag)c.child.return=c,c=c.child;else{if(c===s)break e;for(;null===c.sibling;){if(null===c.return||c.return===s)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}r?(l=n,s=a.stateNode,8===l.nodeType?l.parentNode.removeChild(s):l.removeChild(s)):n.removeChild(a.stateNode)}else if(4===a.tag){if(null!==a.child){n=a.stateNode.containerInfo,r=!0,a.child.return=a,a=a.child;continue}}else if(yl(e,a),null!==a.child){a.child.return=a,a=a.child;continue}if(a===t)break;for(;null===a.sibling;){if(null===a.return||a.return===t)return;4===(a=a.return).tag&&(o=!1)}a.sibling.return=a.return,a=a.sibling}}function Tl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:var n=t.updateQueue;if(null!==(n=null!==n?n.lastEffect:null)){var r=n=n.next;do{3==(3&r.tag)&&(e=r.destroy,r.destroy=void 0,void 0!==e&&e()),r=r.next}while(r!==n)}return;case 1:case 12:case 17:return;case 5:if(null!=(n=t.stateNode)){r=t.memoizedProps;var a=null!==e?e.memoizedProps:r;e=t.type;var o=t.updateQueue;if(t.updateQueue=null,null!==o){for(n[Xr]=r,"input"===e&&"radio"===r.type&&null!=r.name&&te(n,r),Ee(e,a),t=Ee(e,r),a=0;a<o.length;a+=2){var l=o[a],s=o[a+1];"style"===l?ke(n,s):"dangerouslySetInnerHTML"===l?ge(n,s):"children"===l?be(n,s):w(n,l,s,t)}switch(e){case"input":ne(n,r);break;case"textarea":ce(n,r);break;case"select":e=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(o=r.value)?ie(n,!!r.multiple,o,!1):e!==!!r.multiple&&(null!=r.defaultValue?ie(n,!!r.multiple,r.defaultValue,!0):ie(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(i(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((n=t.stateNode).hydrate&&(n.hydrate=!1,kt(n.containerInfo)));case 13:return null!==t.memoizedState&&(Gl=$a(),vl(t.child,!0)),void Cl(t);case 19:return void Cl(t);case 23:case 24:return void vl(t,null!==t.memoizedState)}throw Error(i(163))}function Cl(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new ml),t.forEach((function(t){var r=$s.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function Al(e,t){return null!==e&&(null===(e=e.memoizedState)||null!==e.dehydrated)&&(null!==(t=t.memoizedState)&&null===t.dehydrated)}var Ll=Math.ceil,Rl=k.ReactCurrentDispatcher,Pl=k.ReactCurrentOwner,Nl=0,Ol=null,Il=null,Dl=0,Ml=0,Bl=sa(0),Fl=0,jl=null,Ul=0,zl=0,$l=0,ql=0,Hl=null,Gl=0,Zl=1/0;function Vl(){Zl=$a()+500}var Wl,Kl=null,Yl=!1,Ql=null,Xl=null,Jl=!1,es=null,ts=90,ns=[],rs=[],as=null,os=0,is=null,ls=-1,ss=0,cs=0,us=null,ds=!1;function ps(){return 0!=(48&Nl)?$a():-1!==ls?ls:ls=$a()}function fs(e){if(0==(2&(e=e.mode)))return 1;if(0==(4&e))return 99===qa()?1:2;if(0===ss&&(ss=Ul),0!==Ka.transition){0!==cs&&(cs=null!==Hl?Hl.pendingLanes:0),e=ss;var t=4186112&~cs;return 0===(t&=-t)&&(0===(t=(e=4186112&~e)&-e)&&(t=8192)),t}return e=qa(),0!=(4&Nl)&&98===e?e=jt(12,ss):e=jt(e=function(e){switch(e){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}(e),ss),e}function ms(e,t,n){if(50<os)throw os=0,is=null,Error(i(185));if(null===(e=hs(e,t)))return null;$t(e,t,n),e===Ol&&($l|=t,4===Fl&&vs(e,Dl));var r=qa();1===t?0!=(8&Nl)&&0==(48&Nl)?ys(e):(gs(e,n),0===Nl&&(Vl(),Va())):(0==(4&Nl)||98!==r&&99!==r||(null===as?as=new Set([e]):as.add(e)),gs(e,n)),Hl=e}function hs(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}function gs(e,t){for(var n=e.callbackNode,r=e.suspendedLanes,a=e.pingedLanes,o=e.expirationTimes,l=e.pendingLanes;0<l;){var s=31-qt(l),c=1<<s,u=o[s];if(-1===u){if(0==(c&r)||0!=(c&a)){u=t,Mt(c);var d=Dt;o[s]=10<=d?u+250:6<=d?u+5e3:-1}}else u<=t&&(e.expiredLanes|=c);l&=~c}if(r=Bt(e,e===Ol?Dl:0),t=Dt,0===r)null!==n&&(n!==Ma&&Ta(n),e.callbackNode=null,e.callbackPriority=0);else{if(null!==n){if(e.callbackPriority===t)return;n!==Ma&&Ta(n)}15===t?(n=ys.bind(null,e),null===Fa?(Fa=[n],ja=xa(Pa,Wa)):Fa.push(n),n=Ma):14===t?n=Za(99,ys.bind(null,e)):(n=function(e){switch(e){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(i(358,e))}}(t),n=Za(n,bs.bind(null,e))),e.callbackPriority=t,e.callbackNode=n}}function bs(e){if(ls=-1,cs=ss=0,0!=(48&Nl))throw Error(i(327));var t=e.callbackNode;if(Ds()&&e.callbackNode!==t)return null;var n=Bt(e,e===Ol?Dl:0);if(0===n)return null;var r=n,a=Nl;Nl|=16;var o=Ts();for(Ol===e&&Dl===r||(Vl(),Es(e,r));;)try{Ls();break}catch(s){xs(e,s)}if(to(),Rl.current=o,Nl=a,null!==Il?r=0:(Ol=null,Dl=0,r=Fl),0!=(Ul&$l))Es(e,0);else if(0!==r){if(2===r&&(Nl|=64,e.hydrate&&(e.hydrate=!1,Zr(e.containerInfo)),0!==(n=Ft(e))&&(r=Cs(e,n))),1===r)throw t=jl,Es(e,0),vs(e,n),gs(e,$a()),t;switch(e.finishedWork=e.current.alternate,e.finishedLanes=n,r){case 0:case 1:throw Error(i(345));case 2:case 5:Ns(e);break;case 3:if(vs(e,n),(62914560&n)===n&&10<(r=Gl+500-$a())){if(0!==Bt(e,0))break;if(((a=e.suspendedLanes)&n)!==n){ps(),e.pingedLanes|=e.suspendedLanes&a;break}e.timeoutHandle=Hr(Ns.bind(null,e),r);break}Ns(e);break;case 4:if(vs(e,n),(4186112&n)===n)break;for(r=e.eventTimes,a=-1;0<n;){var l=31-qt(n);o=1<<l,(l=r[l])>a&&(a=l),n&=~o}if(n=a,10<(n=(120>(n=$a()-n)?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*Ll(n/1960))-n)){e.timeoutHandle=Hr(Ns.bind(null,e),n);break}Ns(e);break;default:throw Error(i(329))}}return gs(e,$a()),e.callbackNode===t?bs.bind(null,e):null}function vs(e,t){for(t&=~ql,t&=~$l,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-qt(t),r=1<<n;e[n]=-1,t&=~r}}function ys(e){if(0!=(48&Nl))throw Error(i(327));if(Ds(),e===Ol&&0!=(e.expiredLanes&Dl)){var t=Dl,n=Cs(e,t);0!=(Ul&$l)&&(n=Cs(e,t=Bt(e,t)))}else n=Cs(e,t=Bt(e,0));if(0!==e.tag&&2===n&&(Nl|=64,e.hydrate&&(e.hydrate=!1,Zr(e.containerInfo)),0!==(t=Ft(e))&&(n=Cs(e,t))),1===n)throw n=jl,Es(e,0),vs(e,t),gs(e,$a()),n;return e.finishedWork=e.current.alternate,e.finishedLanes=t,Ns(e),gs(e,$a()),null}function ws(e,t){var n=Nl;Nl|=1;try{return e(t)}finally{0===(Nl=n)&&(Vl(),Va())}}function ks(e,t){var n=Nl;Nl&=-2,Nl|=8;try{return e(t)}finally{0===(Nl=n)&&(Vl(),Va())}}function _s(e,t){ua(Bl,Ml),Ml|=t,Ul|=t}function Ss(){Ml=Bl.current,ca(Bl)}function Es(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,Gr(n)),null!==Il)for(n=Il.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&ba();break;case 3:Io(),ca(fa),ca(pa),Ko();break;case 5:Mo(r);break;case 4:Io();break;case 13:case 19:ca(Bo);break;case 10:no(r);break;case 23:case 24:Ss()}n=n.return}Ol=e,Il=Zs(e.current,null),Dl=Ml=Ul=t,Fl=0,jl=null,ql=$l=zl=0}function xs(e,t){for(;;){var n=Il;try{if(to(),Yo.current=Pi,ni){for(var r=Jo.memoizedState;null!==r;){var a=r.queue;null!==a&&(a.pending=null),r=r.next}ni=!1}if(Xo=0,ti=ei=Jo=null,ri=!1,Pl.current=null,null===n||null===n.return){Fl=1,jl=t,Il=null;break}e:{var o=e,i=n.return,l=n,s=t;if(t=Dl,l.flags|=2048,l.firstEffect=l.lastEffect=null,null!==s&&"object"==typeof s&&"function"==typeof s.then){var c=s;if(0==(2&l.mode)){var u=l.alternate;u?(l.updateQueue=u.updateQueue,l.memoizedState=u.memoizedState,l.lanes=u.lanes):(l.updateQueue=null,l.memoizedState=null)}var d=0!=(1&Bo.current),p=i;do{var f;if(f=13===p.tag){var m=p.memoizedState;if(null!==m)f=null!==m.dehydrated;else{var h=p.memoizedProps;f=void 0!==h.fallback&&(!0!==h.unstable_avoidThisFallback||!d)}}if(f){var g=p.updateQueue;if(null===g){var b=new Set;b.add(c),p.updateQueue=b}else g.add(c);if(0==(2&p.mode)){if(p.flags|=64,l.flags|=16384,l.flags&=-2981,1===l.tag)if(null===l.alternate)l.tag=17;else{var v=co(-1,1);v.tag=2,uo(l,v)}l.lanes|=1;break e}s=void 0,l=t;var y=o.pingCache;if(null===y?(y=o.pingCache=new dl,s=new Set,y.set(c,s)):void 0===(s=y.get(c))&&(s=new Set,y.set(c,s)),!s.has(l)){s.add(l);var w=zs.bind(null,o,c,l);c.then(w,w)}p.flags|=4096,p.lanes=t;break e}p=p.return}while(null!==p);s=Error((V(l.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.")}5!==Fl&&(Fl=2),s=cl(s,l),p=i;do{switch(p.tag){case 3:o=s,p.flags|=4096,t&=-t,p.lanes|=t,po(p,pl(0,o,t));break e;case 1:o=s;var k=p.type,_=p.stateNode;if(0==(64&p.flags)&&("function"==typeof k.getDerivedStateFromError||null!==_&&"function"==typeof _.componentDidCatch&&(null===Xl||!Xl.has(_)))){p.flags|=4096,t&=-t,p.lanes|=t,po(p,fl(p,o,t));break e}}p=p.return}while(null!==p)}Ps(n)}catch(S){t=S,Il===n&&null!==n&&(Il=n=n.return);continue}break}}function Ts(){var e=Rl.current;return Rl.current=Pi,null===e?Pi:e}function Cs(e,t){var n=Nl;Nl|=16;var r=Ts();for(Ol===e&&Dl===t||Es(e,t);;)try{As();break}catch(a){xs(e,a)}if(to(),Nl=n,Rl.current=r,null!==Il)throw Error(i(261));return Ol=null,Dl=0,Fl}function As(){for(;null!==Il;)Rs(Il)}function Ls(){for(;null!==Il&&!Ca();)Rs(Il)}function Rs(e){var t=Wl(e.alternate,e,Ml);e.memoizedProps=e.pendingProps,null===t?Ps(e):Il=t,Pl.current=null}function Ps(e){var t=e;do{var n=t.alternate;if(e=t.return,0==(2048&t.flags)){if(null!==(n=ll(n,t,Ml)))return void(Il=n);if(24!==(n=t).tag&&23!==n.tag||null===n.memoizedState||0!=(1073741824&Ml)||0==(4&n.mode)){for(var r=0,a=n.child;null!==a;)r|=a.lanes|a.childLanes,a=a.sibling;n.childLanes=r}null!==e&&0==(2048&e.flags)&&(null===e.firstEffect&&(e.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1<t.flags&&(null!==e.lastEffect?e.lastEffect.nextEffect=t:e.firstEffect=t,e.lastEffect=t))}else{if(null!==(n=sl(t)))return n.flags&=2047,void(Il=n);null!==e&&(e.firstEffect=e.lastEffect=null,e.flags|=2048)}if(null!==(t=t.sibling))return void(Il=t);Il=t=e}while(null!==t);0===Fl&&(Fl=5)}function Ns(e){var t=qa();return Ga(99,Os.bind(null,e,t)),null}function Os(e,t){do{Ds()}while(null!==es);if(0!=(48&Nl))throw Error(i(327));var n=e.finishedWork;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(i(177));e.callbackNode=null;var r=n.lanes|n.childLanes,a=r,o=e.pendingLanes&~a;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=a,e.mutableReadLanes&=a,e.entangledLanes&=a,a=e.entanglements;for(var l=e.eventTimes,s=e.expirationTimes;0<o;){var c=31-qt(o),u=1<<c;a[c]=0,l[c]=-1,s[c]=-1,o&=~u}if(null!==as&&0==(24&r)&&as.has(e)&&as.delete(e),e===Ol&&(Il=Ol=null,Dl=0),1<n.flags?null!==n.lastEffect?(n.lastEffect.nextEffect=n,r=n.firstEffect):r=n:r=n.firstEffect,null!==r){if(a=Nl,Nl|=32,Pl.current=null,Ur=Wt,gr(l=hr())){if("selectionStart"in l)s={start:l.selectionStart,end:l.selectionEnd};else e:if(s=(s=l.ownerDocument)&&s.defaultView||window,(u=s.getSelection&&s.getSelection())&&0!==u.rangeCount){s=u.anchorNode,o=u.anchorOffset,c=u.focusNode,u=u.focusOffset;try{s.nodeType,c.nodeType}catch(T){s=null;break e}var d=0,p=-1,f=-1,m=0,h=0,g=l,b=null;t:for(;;){for(var v;g!==s||0!==o&&3!==g.nodeType||(p=d+o),g!==c||0!==u&&3!==g.nodeType||(f=d+u),3===g.nodeType&&(d+=g.nodeValue.length),null!==(v=g.firstChild);)b=g,g=v;for(;;){if(g===l)break t;if(b===s&&++m===o&&(p=d),b===c&&++h===u&&(f=d),null!==(v=g.nextSibling))break;b=(g=b).parentNode}g=v}s=-1===p||-1===f?null:{start:p,end:f}}else s=null;s=s||{start:0,end:0}}else s=null;zr={focusedElem:l,selectionRange:s},Wt=!1,us=null,ds=!1,Kl=r;do{try{Is()}catch(T){if(null===Kl)throw Error(i(330));Us(Kl,T),Kl=Kl.nextEffect}}while(null!==Kl);us=null,Kl=r;do{try{for(l=e;null!==Kl;){var y=Kl.flags;if(16&y&&be(Kl.stateNode,""),128&y){var w=Kl.alternate;if(null!==w){var k=w.ref;null!==k&&("function"==typeof k?k(null):k.current=null)}}switch(1038&y){case 2:_l(Kl),Kl.flags&=-3;break;case 6:_l(Kl),Kl.flags&=-3,Tl(Kl.alternate,Kl);break;case 1024:Kl.flags&=-1025;break;case 1028:Kl.flags&=-1025,Tl(Kl.alternate,Kl);break;case 4:Tl(Kl.alternate,Kl);break;case 8:xl(l,s=Kl);var _=s.alternate;wl(s),null!==_&&wl(_)}Kl=Kl.nextEffect}}catch(T){if(null===Kl)throw Error(i(330));Us(Kl,T),Kl=Kl.nextEffect}}while(null!==Kl);if(k=zr,w=hr(),y=k.focusedElem,l=k.selectionRange,w!==y&&y&&y.ownerDocument&&mr(y.ownerDocument.documentElement,y)){null!==l&&gr(y)&&(w=l.start,void 0===(k=l.end)&&(k=w),"selectionStart"in y?(y.selectionStart=w,y.selectionEnd=Math.min(k,y.value.length)):(k=(w=y.ownerDocument||document)&&w.defaultView||window).getSelection&&(k=k.getSelection(),s=y.textContent.length,_=Math.min(l.start,s),l=void 0===l.end?_:Math.min(l.end,s),!k.extend&&_>l&&(s=l,l=_,_=s),s=fr(y,_),o=fr(y,l),s&&o&&(1!==k.rangeCount||k.anchorNode!==s.node||k.anchorOffset!==s.offset||k.focusNode!==o.node||k.focusOffset!==o.offset)&&((w=w.createRange()).setStart(s.node,s.offset),k.removeAllRanges(),_>l?(k.addRange(w),k.extend(o.node,o.offset)):(w.setEnd(o.node,o.offset),k.addRange(w))))),w=[];for(k=y;k=k.parentNode;)1===k.nodeType&&w.push({element:k,left:k.scrollLeft,top:k.scrollTop});for("function"==typeof y.focus&&y.focus(),y=0;y<w.length;y++)(k=w[y]).element.scrollLeft=k.left,k.element.scrollTop=k.top}Wt=!!Ur,zr=Ur=null,e.current=n,Kl=r;do{try{for(y=e;null!==Kl;){var S=Kl.flags;if(36&S&&bl(y,Kl.alternate,Kl),128&S){w=void 0;var E=Kl.ref;if(null!==E){var x=Kl.stateNode;Kl.tag,w=x,"function"==typeof E?E(w):E.current=w}}Kl=Kl.nextEffect}}catch(T){if(null===Kl)throw Error(i(330));Us(Kl,T),Kl=Kl.nextEffect}}while(null!==Kl);Kl=null,Ba(),Nl=a}else e.current=n;if(Jl)Jl=!1,es=e,ts=t;else for(Kl=r;null!==Kl;)t=Kl.nextEffect,Kl.nextEffect=null,8&Kl.flags&&((S=Kl).sibling=null,S.stateNode=null),Kl=t;if(0===(r=e.pendingLanes)&&(Xl=null),1===r?e===is?os++:(os=0,is=e):os=0,n=n.stateNode,Sa&&"function"==typeof Sa.onCommitFiberRoot)try{Sa.onCommitFiberRoot(_a,n,void 0,64==(64&n.current.flags))}catch(T){}if(gs(e,$a()),Yl)throw Yl=!1,e=Ql,Ql=null,e;return 0!=(8&Nl)||Va(),null}function Is(){for(;null!==Kl;){var e=Kl.alternate;ds||null===us||(0!=(8&Kl.flags)?Je(Kl,us)&&(ds=!0):13===Kl.tag&&Al(e,Kl)&&Je(Kl,us)&&(ds=!0));var t=Kl.flags;0!=(256&t)&&gl(e,Kl),0==(512&t)||Jl||(Jl=!0,Za(97,(function(){return Ds(),null}))),Kl=Kl.nextEffect}}function Ds(){if(90!==ts){var e=97<ts?97:ts;return ts=90,Ga(e,Fs)}return!1}function Ms(e,t){ns.push(t,e),Jl||(Jl=!0,Za(97,(function(){return Ds(),null})))}function Bs(e,t){rs.push(t,e),Jl||(Jl=!0,Za(97,(function(){return Ds(),null})))}function Fs(){if(null===es)return!1;var e=es;if(es=null,0!=(48&Nl))throw Error(i(331));var t=Nl;Nl|=32;var n=rs;rs=[];for(var r=0;r<n.length;r+=2){var a=n[r],o=n[r+1],l=a.destroy;if(a.destroy=void 0,"function"==typeof l)try{l()}catch(c){if(null===o)throw Error(i(330));Us(o,c)}}for(n=ns,ns=[],r=0;r<n.length;r+=2){a=n[r],o=n[r+1];try{var s=a.create;a.destroy=s()}catch(c){if(null===o)throw Error(i(330));Us(o,c)}}for(s=e.current.firstEffect;null!==s;)e=s.nextEffect,s.nextEffect=null,8&s.flags&&(s.sibling=null,s.stateNode=null),s=e;return Nl=t,Va(),!0}function js(e,t,n){uo(e,t=pl(0,t=cl(n,t),1)),t=ps(),null!==(e=hs(e,1))&&($t(e,1,t),gs(e,t))}function Us(e,t){if(3===e.tag)js(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){js(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Xl||!Xl.has(r))){var a=fl(n,e=cl(t,e),1);if(uo(n,a),a=ps(),null!==(n=hs(n,1)))$t(n,1,a),gs(n,a);else if("function"==typeof r.componentDidCatch&&(null===Xl||!Xl.has(r)))try{r.componentDidCatch(t,e)}catch(o){}break}}n=n.return}}function zs(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=ps(),e.pingedLanes|=e.suspendedLanes&n,Ol===e&&(Dl&n)===n&&(4===Fl||3===Fl&&(62914560&Dl)===Dl&&500>$a()-Gl?Es(e,0):ql|=n),gs(e,t)}function $s(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(0==(2&(t=e.mode))?t=1:0==(4&t)?t=99===qa()?1:2:(0===ss&&(ss=Ul),0===(t=Ut(62914560&~ss))&&(t=4194304))),n=ps(),null!==(e=hs(e,t))&&($t(e,t,n),gs(e,n))}function qs(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Hs(e,t,n,r){return new qs(e,t,n,r)}function Gs(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Zs(e,t){var n=e.alternate;return null===n?((n=Hs(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Vs(e,t,n,r,a,o){var l=2;if(r=e,"function"==typeof e)Gs(e)&&(l=1);else if("string"==typeof e)l=5;else e:switch(e){case E:return Ws(n.children,a,o,t);case M:l=8,a|=16;break;case x:l=8,a|=1;break;case T:return(e=Hs(12,n,t,8|a)).elementType=T,e.type=T,e.lanes=o,e;case R:return(e=Hs(13,n,t,a)).type=R,e.elementType=R,e.lanes=o,e;case P:return(e=Hs(19,n,t,a)).elementType=P,e.lanes=o,e;case B:return Ks(n,a,o,t);case F:return(e=Hs(24,n,t,a)).elementType=F,e.lanes=o,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case C:l=10;break e;case A:l=9;break e;case L:l=11;break e;case N:l=14;break e;case O:l=16,r=null;break e;case I:l=22;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Hs(l,n,t,a)).elementType=e,t.type=r,t.lanes=o,t}function Ws(e,t,n,r){return(e=Hs(7,e,r,t)).lanes=n,e}function Ks(e,t,n,r){return(e=Hs(23,e,r,t)).elementType=B,e.lanes=n,e}function Ys(e,t,n){return(e=Hs(6,e,null,t)).lanes=n,e}function Qs(e,t,n){return(t=Hs(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Xs(e,t,n){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=zt(0),this.expirationTimes=zt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=zt(0),this.mutableSourceEagerHydrationData=null}function Js(e,t,n,r){var a=t.current,o=ps(),l=fs(a);e:if(n){t:{if(Ke(n=n._reactInternals)!==n||1!==n.tag)throw Error(i(170));var s=n;do{switch(s.tag){case 3:s=s.stateNode.context;break t;case 1:if(ga(s.type)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break t}}s=s.return}while(null!==s);throw Error(i(171))}if(1===n.tag){var c=n.type;if(ga(c)){n=ya(n,c,s);break e}}n=s}else n=da;return null===t.context?t.context=n:t.pendingContext=n,(t=co(o,l)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),uo(a,t),ms(a,l,o),l}function ec(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tc(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function nc(e,t){tc(e,t),(e=e.alternate)&&tc(e,t)}function rc(e,t,n){var r=null!=n&&null!=n.hydrationOptions&&n.hydrationOptions.mutableSources||null;if(n=new Xs(e,t,null!=n&&!0===n.hydrate),t=Hs(3,null,null,2===t?7:1===t?3:0),n.current=t,t.stateNode=n,lo(t),e[Jr]=n.current,Pr(8===e.nodeType?e.parentNode:e),r)for(e=0;e<r.length;e++){var a=(t=r[e])._getVersion;a=a(t._source),null==n.mutableSourceEagerHydrationData?n.mutableSourceEagerHydrationData=[t,a]:n.mutableSourceEagerHydrationData.push(t,a)}this._internalRoot=n}function ac(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function oc(e,t,n,r,a){var o=n._reactRootContainer;if(o){var i=o._internalRoot;if("function"==typeof a){var l=a;a=function(){var e=ec(i);l.call(e)}}Js(t,i,e,a)}else{if(o=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new rc(e,0,t?{hydrate:!0}:void 0)}(n,r),i=o._internalRoot,"function"==typeof a){var s=a;a=function(){var e=ec(i);s.call(e)}}ks((function(){Js(t,i,e,a)}))}return ec(i)}function ic(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!ac(t))throw Error(i(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:S,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}Wl=function(e,t,n){var r=t.lanes;if(null!==e)if(e.memoizedProps!==t.pendingProps||fa.current)Mi=!0;else{if(0==(n&r)){switch(Mi=!1,t.tag){case 3:Zi(t),Vo();break;case 5:Do(t);break;case 1:ga(t.type)&&wa(t);break;case 4:Oo(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value;var a=t.type._context;ua(Qa,a._currentValue),a._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!=(n&t.child.childLanes)?Xi(e,t,n):(ua(Bo,1&Bo.current),null!==(t=ol(e,t,n))?t.sibling:null);ua(Bo,1&Bo.current);break;case 19:if(r=0!=(n&t.childLanes),0!=(64&e.flags)){if(r)return al(e,t,n);t.flags|=64}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),ua(Bo,Bo.current),r)break;return null;case 23:case 24:return t.lanes=0,zi(e,t,n)}return ol(e,t,n)}Mi=0!=(16384&e.flags)}else Mi=!1;switch(t.lanes=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=ha(t,pa.current),ao(t,n),a=ii(null,t,r,e,a,n),t.flags|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,ga(r)){var o=!0;wa(t)}else o=!1;t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,lo(t);var l=r.getDerivedStateFromProps;"function"==typeof l&&go(t,r,l,e),a.updater=bo,t.stateNode=a,a._reactInternals=t,ko(t,r,e,n),t=Gi(null,t,r,!0,o,n)}else t.tag=0,Bi(null,t,a,n),t=t.child;return t;case 16:a=t.elementType;e:{switch(null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=(o=a._init)(a._payload),t.type=a,o=t.tag=function(e){if("function"==typeof e)return Gs(e)?1:0;if(null!=e){if((e=e.$$typeof)===L)return 11;if(e===N)return 14}return 2}(a),e=Ya(a,e),o){case 0:t=qi(null,t,a,e,n);break e;case 1:t=Hi(null,t,a,e,n);break e;case 11:t=Fi(null,t,a,e,n);break e;case 14:t=ji(null,t,a,Ya(a.type,e),r,n);break e}throw Error(i(306,a,""))}return t;case 0:return r=t.type,a=t.pendingProps,qi(e,t,r,a=t.elementType===r?a:Ya(r,a),n);case 1:return r=t.type,a=t.pendingProps,Hi(e,t,r,a=t.elementType===r?a:Ya(r,a),n);case 3:if(Zi(t),r=t.updateQueue,null===e||null===r)throw Error(i(282));if(r=t.pendingProps,a=null!==(a=t.memoizedState)?a.element:null,so(e,t),fo(t,r,null,n),(r=t.memoizedState.element)===a)Vo(),t=ol(e,t,n);else{if((o=(a=t.stateNode).hydrate)&&(Uo=Vr(t.stateNode.containerInfo.firstChild),jo=t,o=zo=!0),o){if(null!=(e=a.mutableSourceEagerHydrationData))for(a=0;a<e.length;a+=2)(o=e[a])._workInProgressVersionPrimary=e[a+1],Wo.push(o);for(n=Co(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|1024,n=n.sibling}else Bi(e,t,r,n),Vo();t=t.child}return t;case 5:return Do(t),null===e&&Ho(t),r=t.type,a=t.pendingProps,o=null!==e?e.memoizedProps:null,l=a.children,qr(r,a)?l=null:null!==o&&qr(r,o)&&(t.flags|=16),$i(e,t),Bi(e,t,l,n),t.child;case 6:return null===e&&Ho(t),null;case 13:return Xi(e,t,n);case 4:return Oo(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=To(t,null,r,n):Bi(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Fi(e,t,r,a=t.elementType===r?a:Ya(r,a),n);case 7:return Bi(e,t,t.pendingProps,n),t.child;case 8:case 12:return Bi(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,a=t.pendingProps,l=t.memoizedProps,o=a.value;var s=t.type._context;if(ua(Qa,s._currentValue),s._currentValue=o,null!==l)if(s=l.value,0===(o=cr(s,o)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(s,o):1073741823))){if(l.children===a.children&&!fa.current){t=ol(e,t,n);break e}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var c=s.dependencies;if(null!==c){l=s.child;for(var u=c.firstContext;null!==u;){if(u.context===r&&0!=(u.observedBits&o)){1===s.tag&&((u=co(-1,n&-n)).tag=2,uo(s,u)),s.lanes|=n,null!==(u=s.alternate)&&(u.lanes|=n),ro(s.return,n),c.lanes|=n;break}u=u.next}}else l=10===s.tag&&s.type===t.type?null:s.child;if(null!==l)l.return=s;else for(l=s;null!==l;){if(l===t){l=null;break}if(null!==(s=l.sibling)){s.return=l.return,l=s;break}l=l.return}s=l}Bi(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=(o=t.pendingProps).children,ao(t,n),r=r(a=oo(a,o.unstable_observedBits)),t.flags|=1,Bi(e,t,r,n),t.child;case 14:return o=Ya(a=t.type,t.pendingProps),ji(e,t,a,o=Ya(a.type,o),r,n);case 15:return Ui(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:Ya(r,a),null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),t.tag=1,ga(r)?(e=!0,wa(t)):e=!1,ao(t,n),yo(t,r,a),ko(t,r,a,n),Gi(null,t,r,!0,e,n);case 19:return al(e,t,n);case 23:case 24:return zi(e,t,n)}throw Error(i(156,t.tag))},rc.prototype.render=function(e){Js(e,this._internalRoot,null,null)},rc.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Js(null,e,null,(function(){t[Jr]=null}))},et=function(e){13===e.tag&&(ms(e,4,ps()),nc(e,4))},tt=function(e){13===e.tag&&(ms(e,67108864,ps()),nc(e,67108864))},nt=function(e){if(13===e.tag){var t=ps(),n=fs(e);ms(e,n,t),nc(e,n)}},rt=function(e,t){return t()},Te=function(e,t,n){switch(t){case"input":if(ne(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=aa(r);if(!a)throw Error(i(90));Q(r),ne(r,a)}}}break;case"textarea":ce(e,n);break;case"select":null!=(t=n.value)&&ie(e,!!n.multiple,t,!1)}},Ne=ws,Oe=function(e,t,n,r,a){var o=Nl;Nl|=4;try{return Ga(98,e.bind(null,t,n,r,a))}finally{0===(Nl=o)&&(Vl(),Va())}},Ie=function(){0==(49&Nl)&&(function(){if(null!==as){var e=as;as=null,e.forEach((function(e){e.expiredLanes|=24&e.pendingLanes,gs(e,$a())}))}Va()}(),Ds())},De=function(e,t){var n=Nl;Nl|=2;try{return e(t)}finally{0===(Nl=n)&&(Vl(),Va())}};var lc={Events:[na,ra,aa,Re,Pe,Ds,{current:!1}]},sc={findFiberByHostInstance:ta,bundleType:0,version:"17.0.2",rendererPackageName:"react-dom"},cc={bundleType:sc.bundleType,version:sc.version,rendererPackageName:sc.rendererPackageName,rendererConfig:sc.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:k.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Xe(e))?null:e.stateNode},findFiberByHostInstance:sc.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var uc=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!uc.isDisabled&&uc.supportsFiber)try{_a=uc.inject(cc),Sa=uc}catch(he){}}t.createPortal=ic,t.hydrate=function(e,t,n){if(!ac(t))throw Error(i(200));return oc(null,e,t,!0,n)}},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var l,s,c,u;if(Array.isArray(e)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(!o(e[s],i[s]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!i.has(s.value[0]))return!1;for(u=e.entries();!(s=u.next()).done;)if(!o(s.value[1],i.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(u=e.entries();!(s=u.next()).done;)if(!i.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(e[s]!==i[s])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((l=(c=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(s=l;0!=s--;)if(!Object.prototype.hasOwnProperty.call(i,c[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!=s--;)if(("_owner"!==c[s]&&"__v"!==c[s]&&"__o"!==c[s]||!e.$$typeof)&&!o(e[c[s]],i[c[s]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>G,ql:()=>J});var r=n(7294),a=n(5697),o=n.n(a),i=n(9590),l=n.n(i),s=n(1143),c=n.n(s),u=n(6774),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(a[n]=e[n]);return a}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(g).map((function(e){return g[e]})),k={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},_=Object.keys(k).reduce((function(e,t){return e[k[t]]=t,e}),{}),S=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},E=function(e){var t=S(e,g.TITLE),n=S(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=S(e,"defaultTitle");return t||r||void 0},x=function(e){return S(e,"onChangeClientState")||function(){}},T=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},C=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var o=r[a].toLowerCase();if(-1!==e.indexOf(o)&&n[o])return t.concat(n)}return t}),[])},A=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,o=Object.keys(e),i=0;i<o.length;i+=1){var l=o[i],s=l.toLowerCase();-1===t.indexOf(s)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===s&&"stylesheet"===e[s].toLowerCase()||(n=s),-1===t.indexOf(l)||"innerHTML"!==l&&"cssText"!==l&&"itemprop"!==l||(n=l)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][c]&&(a[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var o=Object.keys(a),i=0;i<o.length;i+=1){var l=o[i],s=p({},r[l],a[l]);r[l]=s}return e}),[]).reverse()},L=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},R=function(e){return Array.isArray(e)?e.join(""):e},P=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},N=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},O=[g.NOSCRIPT,g.SCRIPT,g.STYLE],I=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},D=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[k[n]||n]=e[n],t}),t)},B=function(e,t){return t.map((function(t,n){var a,o=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=k[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]})),r.createElement(e,o)}))},F=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,o=M(n,a),[r.createElement(g.TITLE,o,e)];var e,n,a,o},toString:function(){return function(e,t,n,r){var a=D(n),o=R(t);return a?"<"+e+' data-rh="true" '+a+">"+I(o,r)+"</"+e+">":"<"+e+' data-rh="true">'+I(o,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return D(t)}};default:return{toComponent:function(){return B(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+I(r[t],n)+'"';return e?e+" "+a:a}),""),o=r.innerHTML||r.cssText||"",i=-1===O.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(i?"/>":">"+o+"</"+e+">")}),"")}(e,t,n)}}}},j=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,o=e.noscriptTags,i=e.styleTags,l=e.title,s=void 0===l?"":l,c=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=P(e.metaTags,y),o=P(t,b),i=P(n,v);return{priorityMethods:{toComponent:function(){return[].concat(B(g.META,a.priority),B(g.LINK,o.priority),B(g.SCRIPT,i.priority))},toString:function(){return F(g.META,a.priority,r)+" "+F(g.LINK,o.priority,r)+" "+F(g.SCRIPT,i.priority,r)}},metaTags:a.default,linkTags:o.default,scriptTags:i.default}}(e);f=m.priorityMethods,u=m.linkTags,d=m.metaTags,p=m.scriptTags}return{priority:f,base:F(g.BASE,t,r),bodyAttributes:F("bodyAttributes",n,r),htmlAttributes:F("htmlAttributes",a,r),link:F(g.LINK,u,r),meta:F(g.META,d,r),noscript:F(g.NOSCRIPT,o,r),script:F(g.SCRIPT,p,r),style:F(g.STYLE,i,r),title:F(g.TITLE,{title:s,titleAttributes:c},r)}},U=[],z=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?U:n.instances},add:function(e){(n.canUseDOM?U:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?U:n.instances).indexOf(e);(n.canUseDOM?U:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=j({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},$=r.createContext({}),q=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),H="undefined"!=typeof document,G=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new z(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement($.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);G.canUseDOM=H,G.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},G.defaultProps={context:{}},G.displayName="HelmetProvider";var Z=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),a=r.querySelectorAll(e+"[data-rh]"),o=[].slice.call(a),i=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),o.some((function(e,t){return n=t,r.isEqualNode(e)}))?o.splice(n,1):i.push(r)})),o.forEach((function(e){return e.parentNode.removeChild(e)})),i.forEach((function(e){return r.appendChild(e)})),{oldTags:o,newTags:i}},V=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],o=[].concat(a),i=Object.keys(t),l=0;l<i.length;l+=1){var s=i[l],c=t[s]||"";n.getAttribute(s)!==c&&n.setAttribute(s,c),-1===a.indexOf(s)&&a.push(s);var u=o.indexOf(s);-1!==u&&o.splice(u,1)}for(var d=o.length-1;d>=0;d-=1)n.removeAttribute(o[d]);a.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},W=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,o=e.metaTags,i=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,c=e.styleTags,u=e.title,d=e.titleAttributes;V(g.BODY,e.bodyAttributes),V(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=R(e)),V(g.TITLE,t)}(u,d);var p={baseTag:Z(g.BASE,n),linkTags:Z(g.LINK,a),metaTags:Z(g.META,o),noscriptTags:Z(g.NOSCRIPT,i),scriptTags:Z(g.SCRIPT,s),styleTags:Z(g.STYLE,c)},f={},m={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(m[e]=p[e].oldTags)})),t&&t(),l(e,f,m)},K=null,Y=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,o=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:C(["href"],e),bodyAttributes:T("bodyAttributes",e),defer:S(e,"defer"),encode:S(e,"encodeSpecialCharacters"),htmlAttributes:T("htmlAttributes",e),linkTags:A(g.LINK,["rel","href"],e),metaTags:A(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:A(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:x(e),scriptTags:A(g.SCRIPT,["src","innerHTML"],e),styleTags:A(g.STYLE,["cssText"],e),title:E(e),titleAttributes:T("titleAttributes",e),prioritizeSeoTags:L(e,"prioritizeSeoTags")});G.canUseDOM?(t=o,K&&cancelAnimationFrame(K),t.defer?K=requestAnimationFrame((function(){W(t,(function(){K=null}))})):(W(t),K=null)):j&&(a=j(o)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);Y.propTypes={context:q.isRequired},Y.displayName="HelmetDispatcher";var Q=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!l()(N(this.props,"helmetData"),N(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,o=e.newChildProps,i=e.nestedChildren;switch(r.type){case g.TITLE:return p({},a,((t={})[r.type]=i,t.titleAttributes=p({},o),t));case g.BODY:return p({},a,{bodyAttributes:p({},o)});case g.HTML:return p({},a,{htmlAttributes:p({},o)});default:return p({},a,((n={})[r.type]=p({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return c()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,o=r.children,i=h(r,Q),l=Object.keys(i).reduce((function(e,t){return e[_[t]||t]=i[t],e}),{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,o),s){case g.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:o})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,X),a=p({},n),o=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!o||o instanceof z||(o=new z(o.context,o.instances)),o?r.createElement(Y,p({},a,{context:o.value,helmetData:void 0})):r.createElement($.Consumer,null,(function(e){return r.createElement(Y,p({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,o=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function k(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case o:case l:case i:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case g:case h:case s:return e;default:return t}}case a:return t}}}function _(e){return k(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=p,t.Fragment=o,t.Lazy=g,t.Memo=h,t.Portal=a,t.Profiler=l,t.StrictMode=i,t.Suspense=f,t.isAsyncMode=function(e){return _(e)||k(e)===u},t.isConcurrentMode=_,t.isContextConsumer=function(e){return k(e)===c},t.isContextProvider=function(e){return k(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return k(e)===p},t.isFragment=function(e){return k(e)===o},t.isLazy=function(e){return k(e)===g},t.isMemo=function(e){return k(e)===h},t.isPortal=function(e){return k(e)===a},t.isProfiler=function(e){return k(e)===l},t.isStrictMode=function(e){return k(e)===i},t.isSuspense=function(e){return k(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===o||e===d||e===l||e===i||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===h||e.$$typeof===s||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===b)},t.typeOf=k},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}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(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}var l=n(7294),s=n(5697),c=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return l.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=i({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),h=null;function g(){return h||(h=e(m.loader)),h.promise}return c.push(g),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),p=d=function(t){function n(n){var r;return o(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),r._loadModule()})),g(),r.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},r}r(n,t),n.preload=function(){return g()};var i=n.prototype;return i.UNSAFE_componentWillMount=function(){this._loadModule()},i.componentDidMount=function(){this._mounted=!0},i._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},i.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},i._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},i.render=function(){return this.state.loading||this.state.error?l.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(l.Component),o(d,"contextTypes",{loadable:s.shape({report:s.func.isRequired})}),p}function h(e){return m(d,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(p,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return l.Children.only(this.props.children)},t}(l.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}o(g,"propTypes",{report:s.func.isRequired}),o(g,"childContextTypes",{loadable:s.shape({report:s.func.isRequired}).isRequired}),h.Capture=g,h.preloadAll=function(){return new Promise((function(e,t){b(c).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){b(u).then(e,e)}))},e.exports=h},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>l,f:()=>i});var r=n(6550),a=n(7462),o=n(7294);function i(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&i(e.routes,t,n)),a})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?o.createElement(r.rs,n,e.map((function(e,n){return o.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.Z)({},n,{},t,{route:e})):o.createElement(e.component,(0,a.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>y,VK:()=>u,rU:()=>g});var r=n(6550),a=n(5068),o=n(7294),i=n(9318),l=n(7462),s=n(3366),c=n(8776),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.lX)(t.props),t}return(0,a.Z)(t,e),t.prototype.render=function(){return o.createElement(r.F0,{history:this.history,children:this.props.children})},t}(o.Component);o.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,i.ob)(e,null,null,t):e},f=function(e){return e},m=o.forwardRef;void 0===m&&(m=f);var h=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,i=(0,s.Z)(e,["innerRef","navigate","onClick"]),c=i.target,u=(0,l.Z)({},i,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==m&&t||n,o.createElement("a",u)}));var g=m((function(e,t){var n=e.component,a=void 0===n?h:n,u=e.replace,g=e.to,b=e.innerRef,v=(0,s.Z)(e,["component","replace","to","innerRef"]);return o.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=e.history,r=p(d(g,e.location),e.location),s=r?n.createHref(r):"",h=(0,l.Z)({},v,{href:s,navigate:function(){var t=d(g,e.location),r=(0,i.Ep)(e.location)===(0,i.Ep)(p(t));(u||r?n.replace:n.push)(t)}});return f!==m?h.ref=t||b:h.innerRef=b,o.createElement(a,h)}))})),b=function(e){return e},v=o.forwardRef;void 0===v&&(v=b);var y=v((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,i=e.activeClassName,u=void 0===i?"active":i,f=e.activeStyle,m=e.className,h=e.exact,y=e.isActive,w=e.location,k=e.sensitive,_=e.strict,S=e.style,E=e.to,x=e.innerRef,T=(0,s.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return o.createElement(r.s6.Consumer,null,(function(e){e||(0,c.Z)(!1);var n=w||e.location,i=p(d(E,n),n),s=i.pathname,C=s&&s.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),A=C?(0,r.LX)(n.pathname,{path:C,exact:h,sensitive:k,strict:_}):null,L=!!(y?y(A,n):A),R="function"==typeof m?m(L):m,P="function"==typeof S?S(L):S;L&&(R=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(R,u),P=(0,l.Z)({},P,f));var N=(0,l.Z)({"aria-current":L&&a||null,className:R,style:P,to:i},T);return b!==v?N.ref=t||x:N.innerRef=x,o.createElement(g,N)}))}))},6550:(e,t,n)=>{"use strict";n.d(t,{AW:()=>E,F0:()=>y,LX:()=>S,TH:()=>O,k6:()=>N,rs:()=>R,s6:()=>v});var r=n(5068),a=n(7294),o=n(5697),i=n.n(o),l=n(9318),s=n(8776),c=n(7462),u=n(4779),d=n.n(u),p=(n(9864),n(3366)),f=(n(8679),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=a.createContext||function(e,t){var n,o,l="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",s=function(e){function n(){for(var t,n,r,a=arguments.length,o=new Array(a),i=0;i<a;i++)o[i]=arguments[i];return(t=e.call.apply(e,[this].concat(o))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.Z)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((o=r)===(i=a)?0!==o||1/o==1/i:o!=o&&i!=i)?n=0:(n="function"==typeof t?t(r,a):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var o,i},a.render=function(){return this.props.children},n}(a.Component);s.childContextTypes=((n={})[l]=i().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},a.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},a.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},a.getValue=function(){return this.context[l]?this.context[l].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return c.contextTypes=((o={})[l]=i().object,o),{Provider:s,Consumer:c}},g=function(e){var t=h();return t.displayName=e,t},b=g("Router-History"),v=g("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(v.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var w={},k=1e4,_=0;function S(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,o=void 0!==a&&a,i=n.strict,l=void 0!==i&&i,s=n.sensitive,c=void 0!==s&&s;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var a=[],o={regexp:d()(e,a,t),keys:a};return _<k&&(r[e]=o,_++),o}(n,{end:o,strict:l,sensitive:c}),a=r.regexp,i=r.keys,s=a.exec(e);if(!s)return null;var u=s[0],p=s.slice(1),f=e===u;return o&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:i.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var E=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?S(n.pathname,e.props):t.match,o=(0,c.Z)({},t,{location:n,match:r}),i=e.props,l=i.children,u=i.component,d=i.render;return Array.isArray(l)&&function(e){return 0===a.Children.count(e)}(l)&&(l=null),a.createElement(v.Provider,{value:o},o.match?l?"function"==typeof l?l(o):l:u?a.createElement(u,o):d?d(o):null:"function"==typeof l?l(o):null)}))},t}(a.Component);function x(e){return"/"===e.charAt(0)?e:"/"+e}function T(e,t){if(!e)return t;var n=x(e);return 0!==t.pathname.indexOf(n)?t:(0,c.Z)({},t,{pathname:t.pathname.substr(n.length)})}function C(e){return"string"==typeof e?e:(0,l.Ep)(e)}function A(e){return function(){(0,s.Z)(!1)}}function L(){}a.Component;var R=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n,r,o=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var i=e.props.path||e.props.from;r=i?S(o.pathname,(0,c.Z)({},e.props,{path:i})):t.match}})),r?a.cloneElement(n,{location:o,computedMatch:r}):null}))},t}(a.Component);var P=a.useContext;function N(){return P(b)}function O(){return P(v).location}},2408:(e,t,n)=>{"use strict";var r=n(7418),a=60103,o=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var i=60109,l=60110,s=60112;t.Suspense=60113;var c=60115,u=60116;if("function"==typeof Symbol&&Symbol.for){var d=Symbol.for;a=d("react.element"),o=d("react.portal"),t.Fragment=d("react.fragment"),t.StrictMode=d("react.strict_mode"),t.Profiler=d("react.profiler"),i=d("react.provider"),l=d("react.context"),s=d("react.forward_ref"),t.Suspense=d("react.suspense"),c=d("react.memo"),u=d("react.lazy")}var p="function"==typeof Symbol&&Symbol.iterator;function f(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h={};function g(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}function b(){}function v(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(f(85));this.updater.enqueueSetState(this,e,t,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=g.prototype;var y=v.prototype=new b;y.constructor=v,r(y,g.prototype),y.isPureReactComponent=!0;var w={current:null},k=Object.prototype.hasOwnProperty,_={key:!0,ref:!0,__self:!0,__source:!0};function S(e,t,n){var r,o={},i=null,l=null;if(null!=t)for(r in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(i=""+t.key),t)k.call(t,r)&&!_.hasOwnProperty(r)&&(o[r]=t[r]);var s=arguments.length-2;if(1===s)o.children=n;else if(1<s){for(var c=Array(s),u=0;u<s;u++)c[u]=arguments[u+2];o.children=c}if(e&&e.defaultProps)for(r in s=e.defaultProps)void 0===o[r]&&(o[r]=s[r]);return{$$typeof:a,type:e,key:i,ref:l,props:o,_owner:w.current}}function E(e){return"object"==typeof e&&null!==e&&e.$$typeof===a}var x=/\/+/g;function T(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function C(e,t,n,r,i){var l=typeof e;"undefined"!==l&&"boolean"!==l||(e=null);var s=!1;if(null===e)s=!0;else switch(l){case"string":case"number":s=!0;break;case"object":switch(e.$$typeof){case a:case o:s=!0}}if(s)return i=i(s=e),e=""===r?"."+T(s,0):r,Array.isArray(i)?(n="",null!=e&&(n=e.replace(x,"$&/")+"/"),C(i,t,n,"",(function(e){return e}))):null!=i&&(E(i)&&(i=function(e,t){return{$$typeof:a,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(i,n+(!i.key||s&&s.key===i.key?"":(""+i.key).replace(x,"$&/")+"/")+e)),t.push(i)),1;if(s=0,r=""===r?".":r+":",Array.isArray(e))for(var c=0;c<e.length;c++){var u=r+T(l=e[c],c);s+=C(l,t,n,u,i)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=p&&e[p]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),c=0;!(l=e.next()).done;)s+=C(l=l.value,t,n,u=r+T(l,c++),i);else if("object"===l)throw t=""+e,Error(f(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t));return s}function A(e,t,n){if(null==e)return e;var r=[],a=0;return C(e,r,"","",(function(e){return t.call(n,e,a++)})),r}function L(e){if(-1===e._status){var t=e._result;t=t(),e._status=0,e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}if(1===e._status)return e._result;throw e._result}var R={current:null};function P(){var e=R.current;if(null===e)throw Error(f(321));return e}var N={ReactCurrentDispatcher:R,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:w,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:A,forEach:function(e,t,n){A(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return A(e,(function(){t++})),t},toArray:function(e){return A(e,(function(e){return e}))||[]},only:function(e){if(!E(e))throw Error(f(143));return e}},t.Component=g,t.PureComponent=v,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=N,t.cloneElement=function(e,t,n){if(null==e)throw Error(f(267,e));var o=r({},e.props),i=e.key,l=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(l=t.ref,s=w.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(u in t)k.call(t,u)&&!_.hasOwnProperty(u)&&(o[u]=void 0===t[u]&&void 0!==c?c[u]:t[u])}var u=arguments.length-2;if(1===u)o.children=n;else if(1<u){c=Array(u);for(var d=0;d<u;d++)c[d]=arguments[d+2];o.children=c}return{$$typeof:a,type:e.type,key:i,ref:l,props:o,_owner:s}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:l,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:i,_context:e},e.Consumer=e},t.createElement=S,t.createFactory=function(e){var t=S.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:s,render:e}},t.isValidElement=E,t.lazy=function(e){return{$$typeof:u,_payload:{_status:-1,_result:e},_init:L}},t.memo=function(e,t){return{$$typeof:c,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return P().useCallback(e,t)},t.useContext=function(e,t){return P().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return P().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return P().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return P().useLayoutEffect(e,t)},t.useMemo=function(e,t){return P().useMemo(e,t)},t.useReducer=function(e,t,n){return P().useReducer(e,t,n)},t.useRef=function(e){return P().useRef(e)},t.useState=function(e){return P().useState(e)},t.version="17.0.2"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},53:(e,t)=>{"use strict";var n,r,a,o;if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;t.unstable_now=function(){return i.now()}}else{var l=Date,s=l.now();t.unstable_now=function(){return l.now()-s}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var c=null,u=null,d=function(){if(null!==c)try{var e=t.unstable_now();c(!0,e),c=null}catch(n){throw setTimeout(d,0),n}};n=function(e){null!==c?setTimeout(n,0,e):(c=e,setTimeout(d,0))},r=function(e,t){u=setTimeout(e,t)},a=function(){clearTimeout(u)},t.unstable_shouldYield=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var p=window.setTimeout,f=window.clearTimeout;if("undefined"!=typeof console){var m=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof m&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var h=!1,g=null,b=-1,v=5,y=0;t.unstable_shouldYield=function(){return t.unstable_now()>=y},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):v=0<e?Math.floor(1e3/e):5};var w=new MessageChannel,k=w.port2;w.port1.onmessage=function(){if(null!==g){var e=t.unstable_now();y=e+v;try{g(!0,e)?k.postMessage(null):(h=!1,g=null)}catch(n){throw k.postMessage(null),n}}else h=!1},n=function(e){g=e,h||(h=!0,k.postMessage(null))},r=function(e,n){b=p((function(){e(t.unstable_now())}),n)},a=function(){f(b),b=-1}}function _(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,a=e[r];if(!(void 0!==a&&0<x(a,t)))break e;e[r]=t,e[n]=a,n=r}}function S(e){return void 0===(e=e[0])?null:e}function E(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length;r<a;){var o=2*(r+1)-1,i=e[o],l=o+1,s=e[l];if(void 0!==i&&0>x(i,n))void 0!==s&&0>x(s,i)?(e[r]=s,e[l]=n,r=l):(e[r]=i,e[o]=n,r=o);else{if(!(void 0!==s&&0>x(s,n)))break e;e[r]=s,e[l]=n,r=l}}}return t}return null}function x(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var T=[],C=[],A=1,L=null,R=3,P=!1,N=!1,O=!1;function I(e){for(var t=S(C);null!==t;){if(null===t.callback)E(C);else{if(!(t.startTime<=e))break;E(C),t.sortIndex=t.expirationTime,_(T,t)}t=S(C)}}function D(e){if(O=!1,I(e),!N)if(null!==S(T))N=!0,n(M);else{var t=S(C);null!==t&&r(D,t.startTime-e)}}function M(e,n){N=!1,O&&(O=!1,a()),P=!0;var o=R;try{for(I(n),L=S(T);null!==L&&(!(L.expirationTime>n)||e&&!t.unstable_shouldYield());){var i=L.callback;if("function"==typeof i){L.callback=null,R=L.priorityLevel;var l=i(L.expirationTime<=n);n=t.unstable_now(),"function"==typeof l?L.callback=l:L===S(T)&&E(T),I(n)}else E(T);L=S(T)}if(null!==L)var s=!0;else{var c=S(C);null!==c&&r(D,c.startTime-n),s=!1}return s}finally{L=null,R=o,P=!1}}var B=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){N||P||(N=!0,n(M))},t.unstable_getCurrentPriorityLevel=function(){return R},t.unstable_getFirstCallbackNode=function(){return S(T)},t.unstable_next=function(e){switch(R){case 1:case 2:case 3:var t=3;break;default:t=R}var n=R;R=t;try{return e()}finally{R=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=B,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=R;R=e;try{return t()}finally{R=n}},t.unstable_scheduleCallback=function(e,o,i){var l=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0<i?l+i:l:i=l,e){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return e={id:A++,callback:o,priorityLevel:e,startTime:i,expirationTime:s=i+s,sortIndex:-1},i>l?(e.sortIndex=i,_(C,e),null===S(T)&&e===S(C)&&(O?a():O=!0,r(D,i-l))):(e.sortIndex=s,_(T,e),N||P||(N=!0,n(M))),e},t.unstable_wrapCallback=function(e){var t=R;return function(){var n=R;R=t;try{return e.apply(this,arguments)}finally{R=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var o=Object.keys(e),i=Object.keys(t);if(o.length!==i.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),s=0;s<o.length;s++){var c=o[s];if(!l(c))return!1;var u=e[c],d=t[c];if(!1===(a=n?n.call(r,u,d,c):void 0)||void 0===a&&u!==d)return!1}return!0}},3250:(e,t,n)=>{"use strict";var r=n(7294);var a="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},o=r.useState,i=r.useEffect,l=r.useLayoutEffect,s=r.useDebugValue;function c(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!a(e,n)}catch(r){return!0}}var u="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=o({inst:{value:n,getSnapshot:t}}),a=r[0].inst,u=r[1];return l((function(){a.value=n,a.getSnapshot=t,c(a)&&u({inst:a})}),[e,n,t]),i((function(){return c(a)&&u({inst:a}),e((function(){c(a)&&u({inst:a})}))}),[e]),s(n),n};t.useSyncExternalStore=void 0!==r.useSyncExternalStore?r.useSyncExternalStore:u},1688:(e,t,n)=>{"use strict";e.exports=n(3250)},6809:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={title:"etherealengine",tagline:"An open source solution for hosting, creating and developing immersive social spaces, built on top of WebXR, React & Feathers.",url:"https://etherealengine.github.io",baseUrl:"/etherealengine-docs/es/",onBrokenLinks:"warn",onBrokenMarkdownLinks:"warn",favicon:"img/favicon.ico",organizationName:"etherealengine",projectName:"etherealengine-docs",i18n:{defaultLocale:"en",locales:["en","es"],path:"i18n",localeConfigs:{}},plugins:[],presets:[["classic",{docs:{sidebarPath:"/home/runner/work/etherealengine/etherealengine/docs/sidebars.js",exclude:["**/_*.{js,jsx,ts,tsx,md,mdx}"],editUrl:"https://github.com/EtherealEngine/etherealengine-docs/blob/master/"},theme:{customCss:"/home/runner/work/etherealengine/etherealengine/docs/src/css/custom.css"}}]],themeConfig:{algolia:{appId:"N5OIDFHT9B",apiKey:"06604779928fc73656c9ae03fae1f0b1",indexName:"etherealengine",contextualSearch:!0,searchParameters:{},searchPagePath:"search"},navbar:{title:"Ethereal Engine",logo:{alt:"Ethereal Engine Logo",src:"img/logo.svg"},items:[{to:"docs/",activeBasePath:"docs",label:"Docs",position:"left"},{href:"https://etherealengine.org/",label:"Ethereal Engine",position:"right"},{type:"localeDropdown",position:"right",dropdownItemsBefore:[],dropdownItemsAfter:[]}],hideOnScroll:!1},footer:{style:"dark",links:[{title:"Social",items:[{label:"Twitter",href:"https://twitter.com/xr_engine"},{label:"Facebook",href:"https://www.facebook.com/xrengine/"},{label:"Discord",href:"https://discord.gg/xrf"}]},{title:"Resources",items:[{label:"Github",href:"https://github.com/etherealengine/etherealengine"},{label:"Npm",href:"https://www.npmjs.com/search?q=%40etherealengine"}]},{title:"More",items:[{label:"Ethereal Engine",href:"https://www.etherealengine.org/"},{label:"Open Collective",href:"https://opencollective.com/etherealengine"}]}],copyright:"Copyright \xa9 2023 Ethereal Engine."},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:[],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},colorMode:{defaultMode:"light",disableSwitch:!1,respectPrefersColorScheme:!1},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},baseUrlIssueBanner:!0,onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>a})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}n.d(t,{Z:()=>r})},8776:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=!0,a="Invariant failed";function o(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,o=n?"".concat(a,": ").concat(n):a;throw new Error(o)}}},7529:e=>{"use strict";e.exports=JSON.parse('{"theme.AnnouncementBar.closeButtonAriaLabel":"Cerrar","theme.BackToTopButton.buttonAriaLabel":"Volver al principio","theme.CodeBlock.copied":"Copiado","theme.CodeBlock.copy":"Copiar","theme.CodeBlock.copyButtonAriaLabel":"Copiar c\xf3digo al portapapeles","theme.CodeBlock.wordWrapToggle":"Toggle word wrap","theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel":"Toggle the collapsible sidebar category \'{label}\'","theme.ErrorPageContent.title":"This page crashed.","theme.ErrorPageContent.tryAgain":"Try again","theme.NavBar.navAriaLabel":"Main","theme.NotFound.p1":"No pudimos encontrar lo que buscaba.","theme.NotFound.p2":"Comun\xedquese con el due\xf1o del sitio que lo vincul\xf3 a la URL original y h\xe1gale saber que su v\xednculo est\xe1 roto.","theme.NotFound.title":"P\xe1gina No Encontrada","theme.TOCCollapsible.toggleButtonLabel":"En esta p\xe1gina","theme.admonition.caution":"caution","theme.admonition.danger":"danger","theme.admonition.info":"info","theme.admonition.note":"note","theme.admonition.tip":"tip","theme.blog.archive.description":"Archivo","theme.blog.archive.title":"Archivo","theme.blog.paginator.navAriaLabel":"Navegaci\xf3n por la p\xe1gina de la lista de blogs ","theme.blog.paginator.newerEntries":"Entradas m\xe1s recientes","theme.blog.paginator.olderEntries":"Entradas m\xe1s antiguas","theme.blog.post.paginator.navAriaLabel":"Barra de paginaci\xf3n de publicaciones del blog","theme.blog.post.paginator.newerPost":"Publicaci\xf3n m\xe1s reciente","theme.blog.post.paginator.olderPost":"Publicaci\xf3n m\xe1s antigua","theme.blog.post.plurals":"Una publicaci\xf3n|{count} publicaciones","theme.blog.post.readMore":"Leer M\xe1s","theme.blog.post.readMoreLabel":"Read more about {title}","theme.blog.post.readingTime.plurals":"Lectura de un minuto|{readingTime} min de lectura","theme.blog.sidebar.navAriaLabel":"Navegaci\xf3n de publicaciones recientes","theme.blog.tagTitle":"{nPosts} etiquetados con \\"{tagName}\\"","theme.colorToggle.ariaLabel":"Switch between dark and light mode (currently {mode})","theme.colorToggle.ariaLabel.mode.dark":"dark mode","theme.colorToggle.ariaLabel.mode.light":"light mode","theme.common.editThisPage":"Editar esta p\xe1gina","theme.common.headingLinkTitle":"Enlace directo al {heading}","theme.common.skipToMainContent":"Saltar al contenido principal","theme.docs.DocCard.categoryDescription":"{count} items","theme.docs.breadcrumbs.home":"Home page","theme.docs.breadcrumbs.navAriaLabel":"Breadcrumbs","theme.docs.paginator.navAriaLabel":"Navegaci\xf3n de p\xe1ginas de documentos","theme.docs.paginator.next":"Siguiente","theme.docs.paginator.previous":"Anterior","theme.docs.sidebar.closeSidebarButtonAriaLabel":"Close navigation bar","theme.docs.sidebar.collapseButtonAriaLabel":"Colapsar barra lateral","theme.docs.sidebar.collapseButtonTitle":"Colapsar barra lateral","theme.docs.sidebar.expandButtonAriaLabel":"Expandir barra lateral","theme.docs.sidebar.expandButtonTitle":"Expandir barra lateral","theme.docs.sidebar.navAriaLabel":"Docs sidebar","theme.docs.sidebar.toggleSidebarButtonAriaLabel":"Toggle navigation bar","theme.docs.tagDocListPageTitle":"{nDocsTagged} con \\"{tagName}\\"","theme.docs.tagDocListPageTitle.nDocsTagged":"Un documento etiquetado|{count} documentos etiquetados","theme.docs.versionBadge.label":"Version: {versionLabel}","theme.docs.versions.latestVersionLinkLabel":"\xfaltima versi\xf3n","theme.docs.versions.latestVersionSuggestionLabel":"Para la documentaci\xf3n actualizada, vea {latestVersionLink} ({versionLabel}).","theme.docs.versions.unmaintainedVersionLabel":"Esta es documentaci\xf3n para {siteTitle} {versionLabel}, que ya no se mantiene activamente.","theme.docs.versions.unreleasedVersionLabel":"Esta es documentaci\xf3n sin liberar para {siteTitle} {versionLabel} versi\xf3n.","theme.lastUpdated.atDate":" en {date}","theme.lastUpdated.byUser":" por {user}","theme.lastUpdated.lastUpdatedAtBy":"\xdaltima actualizaci\xf3n{atDate}{byUser}","theme.navbar.mobileLanguageDropdown.label":"Languages","theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel":"\u2190 Volver al men\xfa principal","theme.navbar.mobileVersionsDropdown.label":"Versiones","theme.tags.tagsListLabel":"Etiquetas:","theme.tags.tagsPageLink":"Ver Todas las Etiquetas","theme.tags.tagsPageTitle":"Etiquetas","theme.SearchBar.label":"Buscar","theme.SearchBar.seeAll":"See all {count} results","theme.SearchModal.errorScreen.helpText":"You might want to check your network connection.","theme.SearchModal.errorScreen.titleText":"Unable to fetch results","theme.SearchModal.footer.closeKeyAriaLabel":"Escape key","theme.SearchModal.footer.closeText":"to close","theme.SearchModal.footer.navigateDownKeyAriaLabel":"Arrow down","theme.SearchModal.footer.navigateText":"to navigate","theme.SearchModal.footer.navigateUpKeyAriaLabel":"Arrow up","theme.SearchModal.footer.searchByText":"Search by","theme.SearchModal.footer.selectKeyAriaLabel":"Enter key","theme.SearchModal.footer.selectText":"to select","theme.SearchModal.noResultsScreen.noResultsText":"No results for","theme.SearchModal.noResultsScreen.reportMissingResultsLinkText":"Let us know.","theme.SearchModal.noResultsScreen.reportMissingResultsText":"Believe this query should return results?","theme.SearchModal.noResultsScreen.suggestedQueryText":"Try searching for","theme.SearchModal.placeholder":"Search docs","theme.SearchModal.searchBox.cancelButtonText":"Cancel","theme.SearchModal.searchBox.resetButtonTitle":"Clear the query","theme.SearchModal.startScreen.favoriteSearchesTitle":"Favorite","theme.SearchModal.startScreen.noRecentSearchesText":"No recent searches","theme.SearchModal.startScreen.recentSearchesTitle":"Recent","theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle":"Remove this search from favorites","theme.SearchModal.startScreen.removeRecentSearchButtonTitle":"Remove this search from history","theme.SearchModal.startScreen.saveRecentSearchButtonTitle":"Save this search","theme.SearchPage.algoliaLabel":"B\xfasqueda por Algolia","theme.SearchPage.documentsFound.plurals":"Un documento encontrado|{count} documentos encontrados","theme.SearchPage.emptyResultsTitle":"B\xfasqueda en la documentaci\xf3n","theme.SearchPage.existingResultsTitle":"Resultados de b\xfasqueda para \\"{query}\\"","theme.SearchPage.fetchingNewResults":"Obteniendo nuevos resultados...","theme.SearchPage.inputLabel":"Buscar","theme.SearchPage.inputPlaceholder":"Escribe tu b\xfasqueda aqu\xed","theme.SearchPage.noResultsText":"No se encontraron resultados"}')},6887:e=>{"use strict";e.exports=JSON.parse('{"/etherealengine-docs/es/markdown-page-de3":{"__comp":"1f391b9e","__context":{"plugin":"cf339e2e"},"content":"393be207"},"/etherealengine-docs/es/search-dc5":{"__comp":"1a4e3797","__context":{"plugin":"33e7527e"}},"/etherealengine-docs/es/docs-f5e":{"__comp":"1be78505","__context":{"plugin":"222ee964"},"versionMetadata":"935f2afb"},"/etherealengine-docs/es/docs/-d34":{"__comp":"17896441","content":"fc66d9af"},"/etherealengine-docs/es/docs/creator/-c2b":{"__comp":"17896441","content":"c538f40f"},"/etherealengine-docs/es/docs/creator/avatars/-7cf":{"__comp":"17896441","content":"6807199d"},"/etherealengine-docs/es/docs/creator/concepts/-bcd":{"__comp":"17896441","content":"0991b023"},"/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locations-d8e":{"__comp":"17896441","content":"b04e8f41"},"/etherealengine-docs/es/docs/creator/development/-487":{"__comp":"17896441","content":"4a62c6ed"},"/etherealengine-docs/es/docs/creator/development/actions_event_sourcing-c7c":{"__comp":"17896441","content":"d05402c5"},"/etherealengine-docs/es/docs/creator/development/behave_graph-fef":{"__comp":"17896441","content":"d519f5a1"},"/etherealengine-docs/es/docs/creator/development/ecs-5ba":{"__comp":"17896441","content":"d43455fa"},"/etherealengine-docs/es/docs/creator/development/networking-7e9":{"__comp":"17896441","content":"0304d7f4"},"/etherealengine-docs/es/docs/creator/development/projects_overview-8a3":{"__comp":"17896441","content":"4a109b8c"},"/etherealengine-docs/es/docs/creator/development/state_management-f5d":{"__comp":"17896441","content":"14d2cd64"},"/etherealengine-docs/es/docs/creator/importing_assets/-287":{"__comp":"17896441","content":"8df89772"},"/etherealengine-docs/es/docs/creator/studio/-903":{"__comp":"17896441","content":"28d03809"},"/etherealengine-docs/es/docs/creator/testing/-005":{"__comp":"17896441","content":"47408852"},"/etherealengine-docs/es/docs/creator/testing/debugging-d27":{"__comp":"17896441","content":"75750052"},"/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceservers-17d":{"__comp":"17896441","content":"d50cf8bd"},"/etherealengine-docs/es/docs/creator/testing/debugging_device_wsl-963":{"__comp":"17896441","content":"271238cb"},"/etherealengine-docs/es/docs/creator/testing/reasonable_code-a47":{"__comp":"17896441","content":"54e37525"},"/etherealengine-docs/es/docs/creator/testing/test_driven_development-dfe":{"__comp":"17896441","content":"cc938c89"},"/etherealengine-docs/es/docs/creator/testing/testing_intro-61d":{"__comp":"17896441","content":"a47a1e93"},"/etherealengine-docs/es/docs/creator/tutorials/-30e":{"__comp":"17896441","content":"917fb754"},"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/-43e":{"__comp":"17896441","content":"4c80fdcb"},"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridge-5ee":{"__comp":"17896441","content":"530a89a7"},"/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridge-958":{"__comp":"17896441","content":"82399a21"},"/etherealengine-docs/es/docs/guest/-d4a":{"__comp":"17896441","content":"a1c60d7a"},"/etherealengine-docs/es/docs/host/-a22":{"__comp":"17896441","content":"bddbf10d"},"/etherealengine-docs/es/docs/host/Admin_Dashboard/-352":{"__comp":"17896441","content":"0f5dde8f"},"/etherealengine-docs/es/docs/host/devops_deployment/-ecb":{"__comp":"17896441","content":"b68e3f8b"},"/etherealengine-docs/es/docs/host/devops_deployment/AWS_setup-4c0":{"__comp":"17896441","content":"58222842"},"/etherealengine-docs/es/docs/host/devops_deployment/database_migrations-90e":{"__comp":"17896441","content":"9a2a3fee"},"/etherealengine-docs/es/docs/host/devops_deployment/docker_desktop-090":{"__comp":"17896441","content":"a91c512d"},"/etherealengine-docs/es/docs/host/devops_deployment/installing_projects-b67":{"__comp":"17896441","content":"0346e14a"},"/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetes-f6b":{"__comp":"17896441","content":"d88112b6"},"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linux-35b":{"__comp":"17896441","content":"c7af7f81"},"/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windows-ce3":{"__comp":"17896441","content":"3c3cda30"},"/etherealengine-docs/es/docs/host/devops_deployment/minikube-134":{"__comp":"17896441","content":"ea08158a"},"/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chart-33b":{"__comp":"17896441","content":"24869598"},"/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projects-8af":{"__comp":"17896441","content":"12905b1d"},"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/-0ab":{"__comp":"17896441","content":"95bfc3a6"},"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/-d30":{"__comp":"17896441","content":"291a898d"},"/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started-ffc":{"__comp":"17896441","content":"4b422948"},"/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deployment-52d":{"__comp":"17896441","content":"dcc1f912"},"/etherealengine-docs/es/docs/host/installation/-246":{"__comp":"17896441","content":"f7429bc1"},"/etherealengine-docs/es/docs/host/installation/advanced_setup-913":{"__comp":"17896441","content":"d7cf77e2"},"/etherealengine-docs/es/docs/host/installation/basic_setup-f4f":{"__comp":"17896441","content":"ebc45004"},"/etherealengine-docs/es/docs/host/installation/docker-06a":{"__comp":"17896441","content":"e988a1b0"},"/etherealengine-docs/es/docs/host/installation/install_troubleshooting-17d":{"__comp":"17896441","content":"46dcad74"},"/etherealengine-docs/es/docs/host/installation/mac_os_x-e5c":{"__comp":"17896441","content":"86c50ec3"},"/etherealengine-docs/es/docs/host/installation/opensearch-426":{"__comp":"17896441","content":"06bf4b13"},"/etherealengine-docs/es/docs/host/installation/running_on_static_IP-af7":{"__comp":"17896441","content":"3ec03ade"},"/etherealengine-docs/es/docs/host/installation/windows-8f7":{"__comp":"17896441","content":"b5eb9e9a"},"/etherealengine-docs/es/docs/host/installation/windows_wsl-e6b":{"__comp":"17896441","content":"15dae980"},"/etherealengine-docs/es/-cfa":{"__comp":"1df93b7f","__context":{"plugin":"cf339e2e"},"config":"5e9f5e1a"}}')}},e=>{e.O(0,[3312],(()=>{return t=9383,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/es/assets/js/main.687acc7d.js.LICENSE.txt b/es/assets/js/main.687acc7d.js.LICENSE.txt new file mode 100644 index 000000000000..eb75d69107c8 --- /dev/null +++ b/es/assets/js/main.687acc7d.js.LICENSE.txt @@ -0,0 +1,63 @@ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/** + * @license React + * use-sync-external-store-shim.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + */ + +/** @license React v0.20.2 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/es/assets/js/runtime~main.5252ab58.js b/es/assets/js/runtime~main.5252ab58.js new file mode 100644 index 000000000000..398a1785c79b --- /dev/null +++ b/es/assets/js/runtime~main.5252ab58.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,c,d,f,t={},r={};function b(e){var a=r[e];if(void 0!==a)return a.exports;var c=r[e]={id:e,loaded:!1,exports:{}};return t[e].call(c.exports,c,c.exports,b),c.loaded=!0,c.exports}b.m=t,b.c=r,e=[],b.O=(a,c,d,f)=>{if(!c){var t=1/0;for(i=0;i<e.length;i++){c=e[i][0],d=e[i][1],f=e[i][2];for(var r=!0,o=0;o<c.length;o++)(!1&f||t>=f)&&Object.keys(b.O).every((e=>b.O[e](c[o])))?c.splice(o--,1):(r=!1,f<t&&(t=f));if(r){e.splice(i--,1);var n=d();void 0!==n&&(a=n)}}return a}f=f||0;for(var i=e.length;i>0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[c,d,f]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var f=Object.create(null);b.r(f);var t={};a=a||[null,c({}),c([]),c(c)];for(var r=2&d&&e;"object"==typeof r&&!~a.indexOf(r);r=c(r))Object.getOwnPropertyNames(r).forEach((a=>t[a]=()=>e[a]));return t.default=()=>e,b.d(f,t),f},b.d=(e,a)=>{for(var c in a)b.o(a,c)&&!b.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,c)=>(b.f[c](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",176:"d88112b6",301:"6807199d",314:"d7cf77e2",401:"222ee964",532:"75750052",543:"b68e3f8b",720:"0346e14a",943:"4a109b8c",1205:"d43455fa",1364:"d50cf8bd",1423:"28d03809",1473:"82399a21",1489:"15dae980",2130:"47408852",2142:"b04e8f41",2345:"12905b1d",2606:"291a898d",2901:"14d2cd64",2984:"33e7527e",3085:"1f391b9e",3113:"fc66d9af",3179:"f7429bc1",3237:"1df93b7f",3573:"24869598",3666:"dcc1f912",3709:"cc938c89",3850:"c538f40f",3881:"4b422948",3976:"0f5dde8f",4380:"c7af7f81",4438:"cf339e2e",4449:"a91c512d",4705:"e988a1b0",4995:"ea08158a",5003:"271238cb",5046:"d519f5a1",5111:"530a89a7",5194:"ebc45004",5229:"9a2a3fee",5459:"95bfc3a6",5520:"46dcad74",5572:"06bf4b13",5624:"4a62c6ed",5992:"a47a1e93",6524:"0991b023",6658:"b5eb9e9a",6718:"54e37525",6916:"3ec03ade",6970:"d05402c5",7053:"917fb754",7414:"393be207",7918:"17896441",7920:"1a4e3797",8511:"4c80fdcb",8620:"8df89772",8625:"86c50ec3",8718:"58222842",8823:"bddbf10d",8949:"a1c60d7a",8953:"0304d7f4",9037:"3c3cda30",9514:"1be78505"}[e]||e)+"."+{53:"eeb7911d",176:"0781129c",272:"9b1a0f8c",301:"393b4448",314:"d0f4d092",401:"1c0e3f8c",532:"b16089c1",543:"bb25d3c1",720:"62b5698b",943:"295ebd36",1205:"4846077f",1364:"2f6b2995",1423:"1287b94d",1426:"3913c64b",1473:"c0302048",1489:"eb3148f9",2130:"8b910eaa",2142:"c4913e66",2345:"d62b8bd9",2606:"88c52616",2901:"5c92038e",2984:"bca6e6d3",3085:"75a9ca1a",3113:"fb62773e",3179:"67e41e76",3237:"7f8f9032",3573:"944c76c9",3666:"b4a1ef2a",3709:"5505f774",3850:"4ff5f4b7",3881:"6f450d33",3976:"b39c071a",4380:"279e5e03",4438:"43e40fa8",4449:"1ac72c7e",4705:"98fbbb7a",4972:"512e2090",4995:"3b7ce41d",5003:"e0da372c",5046:"105895aa",5111:"4439efde",5194:"77289e03",5229:"536081b5",5459:"66363db1",5520:"58580c48",5572:"b597313d",5624:"658385a6",5992:"831bfca6",6524:"73048e9e",6658:"b0e266ee",6718:"76419b03",6916:"f32e4786",6945:"326f966e",6970:"90cf9c7a",7053:"32092b78",7414:"6e6ea16e",7918:"07f91ca7",7920:"dd8146f2",8511:"270f98c5",8620:"b7fc7bc7",8625:"231a1b34",8718:"4c3c6afe",8823:"e6a24914",8894:"2c471ab3",8949:"7ce3e8be",8953:"280ccf8d",9037:"3166b617",9514:"dc6e92dc"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},f="@etherealengine/docs:",b.l=(e,a,c,t)=>{if(d[e])d[e].push(a);else{var r,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var l=n[i];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==f+c){r=l;break}}r||(o=!0,(r=document.createElement("script")).charset="utf-8",r.timeout=120,b.nc&&r.setAttribute("nonce",b.nc),r.setAttribute("data-webpack",f+c),r.src=e),d[e]=[a];var u=(a,c)=>{r.onerror=r.onload=null,clearTimeout(s);var f=d[e];if(delete d[e],r.parentNode&&r.parentNode.removeChild(r),f&&f.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=u.bind(null,r.onerror),r.onload=u.bind(null,r.onload),o&&document.head.appendChild(r)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/etherealengine-docs/es/",b.gca=function(e){return e={17896441:"7918",24869598:"3573",47408852:"2130",58222842:"8718",75750052:"532","935f2afb":"53",d88112b6:"176","6807199d":"301",d7cf77e2:"314","222ee964":"401",b68e3f8b:"543","0346e14a":"720","4a109b8c":"943",d43455fa:"1205",d50cf8bd:"1364","28d03809":"1423","82399a21":"1473","15dae980":"1489",b04e8f41:"2142","12905b1d":"2345","291a898d":"2606","14d2cd64":"2901","33e7527e":"2984","1f391b9e":"3085",fc66d9af:"3113",f7429bc1:"3179","1df93b7f":"3237",dcc1f912:"3666",cc938c89:"3709",c538f40f:"3850","4b422948":"3881","0f5dde8f":"3976",c7af7f81:"4380",cf339e2e:"4438",a91c512d:"4449",e988a1b0:"4705",ea08158a:"4995","271238cb":"5003",d519f5a1:"5046","530a89a7":"5111",ebc45004:"5194","9a2a3fee":"5229","95bfc3a6":"5459","46dcad74":"5520","06bf4b13":"5572","4a62c6ed":"5624",a47a1e93:"5992","0991b023":"6524",b5eb9e9a:"6658","54e37525":"6718","3ec03ade":"6916",d05402c5:"6970","917fb754":"7053","393be207":"7414","1a4e3797":"7920","4c80fdcb":"8511","8df89772":"8620","86c50ec3":"8625",bddbf10d:"8823",a1c60d7a:"8949","0304d7f4":"8953","3c3cda30":"9037","1be78505":"9514"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,3312:0};b.f.j=(a,c)=>{var d=b.o(e,a)?e[a]:void 0;if(0!==d)if(d)c.push(d[2]);else if(/^(1303|3312)$/.test(a))e[a]=0;else{var f=new Promise(((c,f)=>d=e[a]=[c,f]));c.push(d[2]=f);var t=b.p+b.u(a),r=new Error;b.l(t,(c=>{if(b.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var f=c&&("load"===c.type?"missing":c.type),t=c&&c.target&&c.target.src;r.message="Loading chunk "+a+" failed.\n("+f+": "+t+")",r.name="ChunkLoadError",r.type=f,r.request=t,d[1](r)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,c)=>{var d,f,t=c[0],r=c[1],o=c[2],n=0;if(t.some((a=>0!==e[a]))){for(d in r)b.o(r,d)&&(b.m[d]=r[d]);if(o)var i=o(b)}for(a&&a(c);n<t.length;n++)f=t[n],b.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return b.O(i)},c=self.webpackChunk_etherealengine_docs=self.webpackChunk_etherealengine_docs||[];c.forEach(a.bind(null,0)),c.push=a.bind(null,c.push.bind(c))})()})(); \ No newline at end of file diff --git a/es/docs/creator/avatars/index.html b/es/docs/creator/avatars/index.html new file mode 100644 index 000000000000..1d550624a9bd --- /dev/null +++ b/es/docs/creator/avatars/index.html @@ -0,0 +1,16 @@ +<!doctype html> +<html lang="es" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-creator/avatars/readme"> +<head> +<meta charset="UTF-8"> +<meta name="generator" content="Docusaurus v2.4.0"> +<title data-rh="true">readme | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/creator/concepts/editor_scenes_locations/index.html b/es/docs/creator/concepts/editor_scenes_locations/index.html new file mode 100644 index 000000000000..9e3d7b4a6c7b --- /dev/null +++ b/es/docs/creator/concepts/editor_scenes_locations/index.html @@ -0,0 +1,16 @@ + + + + + +Studio & Locations | etherealengine + + + + +
+

Studio & Locations

Scene Studio

Navigating to /studio will show you the projects page, where you can open existing projects or create a new one.

Opening a project will route you to /studio/<projectName> where the project studio will load. From here, you can open a scene, which will route you again to /studio/<projectName>/<sceneName>

The scene consists of a list of 'nodes' which act as templates / prefabs. These are what you would normally expect in a scene studio, such as models, colliders and audio, but we also support a wide range of integrations, such as shopify, wordpress and even portals to let you traverse between worlds.

To save a scene with Ctrl+S or in the top left Hamburger menu.

Locations & Instances

Locations can be thought of as instantiations of scene. This is how you connect your scene to a shared session.

Locations can be loaded via the /location/<locationName> route, where locationName is the name of the location. By default, the locations default, apartment and sky-station are added.

An instance is an individual session running at a location, in which users are connected together in real time. This allows the deployment to scale events and locations to potentially millions of concurrent users without having to support them all on a single instance.

There are two types of instances: world instances and media instances. World instances handle the spatial objects in the scene, such as avatars, vehicles and grabbables. Media instances handle realtime audio, video and screenshare.

Media instances can be tied to a location, or exist ephemerally as a group call, called parties.

Instances can also be customised with the 'matchmaker' functionality to create private rooms.

Adding a new location is done from /admin/locations route, and live instances can be viewed from /admin/instances.

+ + + + \ No newline at end of file diff --git a/es/docs/creator/concepts/index.html b/es/docs/creator/concepts/index.html new file mode 100644 index 000000000000..8338e17c11e9 --- /dev/null +++ b/es/docs/creator/concepts/index.html @@ -0,0 +1,16 @@ + + + + + +Concepts | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/creator/development/actions_event_sourcing/index.html b/es/docs/creator/development/actions_event_sourcing/index.html new file mode 100644 index 000000000000..9fca99d9f72b --- /dev/null +++ b/es/docs/creator/development/actions_event_sourcing/index.html @@ -0,0 +1,16 @@ + + + + + +Event Sourcing | etherealengine + + + + +
+

Event Sourcing

Actions

Actions are a way to control state changes in your application. Once defined, they can be dispatched, which will then populate the outgoing queue to be processed on the next frame.

All actions are dispatched to a topic, by default this is the default topic. Topics are used to specify that actions are to be routed to specific networks.

When an action is dispatched, it is added to the incoming action queue. If it's topic is networked, it is also added to the outgoing queue for it's topic.

At the end of the animation frame, any actions in a network topic's outgoing queue are sent to that topic's network.

If the peer is the host of a networked action's topic, the action is sent to all other peers, otherwise it is just sent to the host. This can be opted out of by specifying the $to property on an action, which informs the host to forward the action only to that user's.

At the start of the next animation frame, action queues are populated with incoming actions. These actions are then processed in the order they were received, by systems in the order the systems are registered.

+ + + + \ No newline at end of file diff --git a/es/docs/creator/development/behave_graph/index.html b/es/docs/creator/development/behave_graph/index.html new file mode 100644 index 000000000000..8548a6ff16d5 --- /dev/null +++ b/es/docs/creator/development/behave_graph/index.html @@ -0,0 +1,30 @@ + + + + + +Introduction | etherealengine + + + + +
+

Introduction

  • Overview
  • Audience

Getting Started

  • Installation
  • Configuration

Code Overview:

  • High-Level Architecture
  • Key Concepts
  • Engine Nodes

Usage

  • Examples

Configuration and Customization

  • Making new nodes

1. Introduction

1.1 Overview

Behavior graphs are expressive, deterministic, and extensible state machines that can encode arbitrarily complex behavior.

Behavior graphs are a popular choice for implementing visual scripting languages. Prominent game engines like Unreal Engine and Unity have adopted behavior graphs as an essential component of their visual scripting systems. For example, Unreal Engine's Blueprints, Unity's Visual Scripting, and NVIDIA Omniverse's OmniGraph rely on behavior graphs to enable game designers and developers to create complex behaviors without writing code directly.

Within the Ethereal Engine, the Behavior Graphs feature plays a pivotal role by providing a no-code interface to the engine and by interacting with the engine while modeling, organizing, controlling and assigning complex behaviors on entities, with ease.

1.2 Audience

Behavior Graphs in the Ethereal engine target developers, designers, artists, and non-technical users. This visual scripting feature enables easy implementation of complex logic and actions for entities without the need for writing scripts. It fosters collaboration and empowers diverse individuals to create immersive experiences and interactive content within the engine.

2. Getting Started

2.1 Installation - at the moment the behavior graph implementation is available on the behave-graph-integration branch in the Ethereal Engine Repository

Clone the branch and follow general Ethereal engine installation steps +general instructions

The Behavior Graphs must be defined in the studio and thus require a user to have admin privileges

2.2 Configuration

The Behave graph is implemented as a component in the engine following the ECS(Entity component system) architecture in the engine.

Users can add and remove a behave graph component from an entity

Step 1: find the behave graph component under the scripting section in the component shelf in the right side of the screen +Step 2:

  1. double click on the component tor drag and drop into scene to add a new entity with the behave graph component into the screen
  2. Drag and drop into the hierarchy panel on another entity to add to scene as child of the selected entity
  3. Drag and drop into properties panel of selected entity to add component to entity

The behave graph properties panel has two properties:

  • Run graph: runs the graph in headless mode as part of the engine
  • Disable graph: disable graph from playing

2.3 Creating your First graph

Before we dive into creating the graph let's take a look at the graph panel

The graph panel consists of the the panel itself, panel buttons, nodes and connections

The default behave graph consists of an

On start event node

On tick event node

Logger node

To navigate across the panel, drag across the surface of the panel

2.3.1 buttons in the graph panel

The buttons panel is location in the bottom left side of the screen

The buttons are as follows

Zoom in: zoom into the graph viewport

Zoom out: zoom out of the graph viewport

Fit view: tries to fit all nodes into the screen at the same time, if not possible it centers the view at the center of all nodes

Lock graph: Toggles ability to graph edit

Help: Opens an instruction modal for making graphs

Load Graph: Opens a modal, user can paste graph json in the input field to load the corresponding graph

Save Graph: Opens a model, user can copy the graph json from the text box and save as needed

Play Graph: runs headful version of the graph connected to the graph editor

2.3.2 Saving Graph

The graph has its own json which is also part of the scene json, therefore the user needs to save the graph in as its own json which then must be saved as a part of the scene

The graph json is autosaved every 5 seconds the graph panel i open and whenever the graph panel is closed (the component unmounts)

The graph and overall changes to the scene must be saved using the save scene option from the main menu

2.3.3 Playing a graph

A graph can be played in two modes, headful and headless,

headful mode play - headful mode, activated by pressing the play button in the graph buttons, graph stops executing when the panel is closed or component unmounts, meant for quick testing, setting scene variables and rapid development

Headless mode play - headless mode, play activated from properties panel, execution does not stop unless play is toggled off again from the properties panel

To play all graphs in the scene the user can use the play scene button from the top toolbar

NOTE: headful and headless plays must be managed separately

Ok finally with all this context, lets add a node

To add a node, right click anywhere on the graph panel

This will open up the node picker select window,

Type in the search input to filter nodes by prefix +Click on the node to add to the panel

Lets add a logger node and connect it to the on tick event

To connect the flow of the nodes , drag from one flow socket to another +There can be only one flow output from one flow output socket

But there can be multiple inputs to a flow input socket

To play the graph click on the play graph button

Well done, outputs to the log can be seen in the dev tools console

TODO: add pictures

  1. Code Overview:

Node Types

  • Events You can implement arbitrary events that start execution: Start, Tick
  • Actions You can implement actions that trigger animations, scene scene variations, or update internal state: Log, Play Gltf animation, Play Audio, Play Video, etc
  • Logic You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes.
  • Queries You can query the state from the system.
  • Flow Control Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop
  • Variables You can create, set and get variable values.
  • Custom Events You can create, listen to and trigger custom events.

3.2 Key Concepts

Nodes - +Connections - +Flow -

Events

Set and Get Scene Properties

Registering nodes

Value Types

Value type Converters

3.3 Engine Nodes

3.3.1 Entity

Teleport Entity +Add Entity +Delete Entity +Get Entity from Scene +Get Camera Entity

3.3.2 Component

Add Component

Delete Component

Get component from registry +Get component from entity

3.3.3 Engine

Play Video

Play Audio

Play Gltf Animations

Get Avatar animations

Fade Camera

Switch Scene

3.3.4 Events

Either in pairs of trigger and listener , or just listener +On Button State

triggerLoadAsset -> onLoadAsset

4. Usage

Add some example screenshots and explain

5.Configuration and Customization

5.1 Making new nodes

Describe the creation of nodes

Making flow nodes +Making Event node +Making Value types

Making Function node

Extending Dependencies

+ + + + \ No newline at end of file diff --git a/es/docs/creator/development/ecs/index.html b/es/docs/creator/development/ecs/index.html new file mode 100644 index 000000000000..df8ab8082ced --- /dev/null +++ b/es/docs/creator/development/ecs/index.html @@ -0,0 +1,16 @@ + + + + + +Entities, Components and Systems | etherealengine + + + + +
+

Entities, Components and Systems

What is an ECS?

ECS refers to the "Entity Component System" architecture paradigm. In this pattern, data is organised into abstract objects called components that allows for composition instead of inheritance. An entity is simply collection of components identified by a number. Systems are functions that operate on these entities and components.

Component Definitions

Components support two types of data: Structure of Arrays and Array of Structures.

Structure of Arrays Component Data

Structure of Arrays is a data layout that stores data in a way that is more cache friendly. It is a good choice for data that is accessed often and in a predictable way, such as transform data.

const TransformComponent = defineComponent({
name: 'TransformComponent',
schema: {
position: Types.f64,
rotation: Types.f64,
scale: Types.f64
}
})

Reactive Component Data

Array of Structures is an implementation unique to Ethereal Engine, using React and Hookstate under the hood, it allows for reactive data binding. This means that when a property is changed, all effects depending on it will be triggered. It is a good choice for data that is accessed infrequently and in an unpredictable way, especially when react style logic is associated with it.

const DebugArrowComponent = defineComponent({
name: 'DebugArrowComponent',

onInit: (entity) => {
return {
color: 0xffffff,
direction: new Vector3(),
position: new Vector3()
}
},

onSet: (entity, component, json) => {
if (!json) return

if (json.color) component.color.set(json.color)
if (json.direction) component.direction.set(json.direction)
if (json.position) component.position.set(json.position)
}
})

onInit

(entity: Entity) => ComponentType<C>

onInit is a function that is called when setComponent is called on an entity that does not have the component in question. It is passed the entity number and should return an object with the initial values for the component.

onSet

entity: Entity, component: ComponentType<C>, json: SerializedComponentType<C>) => void

onSet is a function that is called each time setComponent is called. It is passed the entity number, the component object and json object. This is how reactive data can be updated in batch, allowing for tighter data flow, such as deserializing scene data.

onRemove

(entity: Entity, component: ComponentType<C>) => void

onRemove is a function that is called when removeComponent is called on an entity that has the component in question. It is passed the entity number and the component object. This is where you would clean up any resources associated with the component.

toJSON

(entity: Entity, component: ComponentType<C>) => SerializedComponentType<C>

toJSON is a function that is called when serializeComponent is called on an entity that has the component in question. It is passed the entity number and the component object. This is where serialized data can be generated, such as for saving a scene.

jsonID

string

jsonID is a string that is used to identify the component in json. It is used when deserializing and serializing scenes.

reactor

function(props: { root: EntityRoot }) => void

reactor specifies a function that exists for the duration of this component instance. This is where you would add any effects that depend on the component.

Update Loop

The engine uses a very similar model to Unity's update loop (found here https://docs.unity3d.com/Manual/ExecutionOrder.html). It has a frame update, called once per frame, of which inside is a fixed update, which operates on an accumulator system. This system ensures a stable number of updates per second independent of the framerate. This means it may have 0 to many updates in a given frame.

Ethereal Engine implements this with pipelines, which are collections of systems to execute in order.

Queries

Queries are used to select entities that have a set of components. They are used to define the entities that a system will operate on. Queries are defined using the defineQuery function.

const query = defineQuery([TransformComponent, GroupComponent])

const entities = query() // returns an array of entity numbers

Queries also have enter and exit derivatives, which are used to define when a combination of components is added or removed from an entity. These are defined using the defineEnterQuery and defineExitQuery functions.

const query = defineQuery([TransformComponent, GroupComponent])

const allEntities = query()
const enterEntities = query.enter()
const exitEntities = query.exit()

Examples

Timer

The follow code snippets, we define a component and a system. The component will hold a property to store the current elapsed time rounded down.

In the initializer of the system, it creates a new entity and adds the component to it. In the execute function of the system, we set the property time on the component of the entity.

This example uses 'Structure of Arrays' (SoA) data structures with bitECS syntax.

const TimerComponent = defineComponent({
name: 'TimerComponent',
schema: {
time: Types.f32
}
})

const timerQuery = defineQuery([TimerComponent])

const execute = () => {
const { deltaSeconds } = getState(EngineState)

for (const entity of timerQuery()) {
TimerComponent.time[entity] += delta
}
}

export const TimerSystem = defineSystem({
uuid: 'TimerSystem',
execute
})

This example uses 'Array of Structures' syntax, with reactive data binding.

const TimerComponent = defineComponent({
name: 'TimerComponent',
onInit: (entity) => {
return {
time: 0
}
},
onSet: (entity, component, json) => {
if (typeof json?.time === 'number') component.time.set(json.time)
},
toJSON: (entity, component) => {
return {
time: component.time.value
}
}
})

const timerQuery = defineQuery([TimerComponent])

const execute = () => {
const { elapsedSeconds } = getState(EngineState)

for (const entity of timerQuery()) {
const timerComponent = getMutableComponent(entity, TimerComponent)
timerComponent.time.set(Math.floor(elapsedSeconds))
}
}

export const TimerSystem = defineSystem({
uuid: 'TimerSystem',
execute
})

References

+ + + + \ No newline at end of file diff --git a/es/docs/creator/development/index.html b/es/docs/creator/development/index.html new file mode 100644 index 000000000000..170d0381eb61 --- /dev/null +++ b/es/docs/creator/development/index.html @@ -0,0 +1,16 @@ + + + + + +Development | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/creator/development/networking/index.html b/es/docs/creator/development/networking/index.html new file mode 100644 index 000000000000..658dba8d5a19 --- /dev/null +++ b/es/docs/creator/development/networking/index.html @@ -0,0 +1,16 @@ + + + + + +Networking | etherealengine + + + + +
+

Networking

Networks

Networks are a way of sharing topic specific data between certain peers. There are two types of networks, world and media networks, and are tied to location instances and media instances respectively.

Users & Peers

Users are unique accounts created in a particular Ethereal Engine deployment. Users can connect to multiple instances, and have multiple peers connected to each instance.

Ownership and Authority

Ownership specifies that a networked entity belongs to a particular user. Ownership cannot be transferred for an entity, the entity must be destroyed and recreated by a new user.

Authority specifies that a networked entity can be controlled by a particular peer. Authority can be transferred between peers, and is done so by sending an authority request action to the owner peer, upon which the owner peer will send an authority transfer action to the requesting peer.

+ + + + \ No newline at end of file diff --git a/es/docs/creator/development/projects_overview/index.html b/es/docs/creator/development/projects_overview/index.html new file mode 100644 index 000000000000..749d9f747374 --- /dev/null +++ b/es/docs/creator/development/projects_overview/index.html @@ -0,0 +1,50 @@ + + + + + +Projects | etherealengine + + + + +
+

Projects

Projects are folders that contain all your custom code, assets and scenes. They +are version controlled using git & github, and can be installed to any deployment +with a single click. (more on that in the next chapter)

Pictured below is an example of 4 projects installed. By default, only the +default-project is installed, which in a production environment is read only. +You can find the default project under /packages/projects/default-project/

In a production environment, the builder process will install all projects +according to the project database table and will download files from the +storage provider. In a local development environment, the local file system is +always the source of truth. Any project folders added or removed from the file +system will be automatically added or removed from the database. This is to +ensure there is no accidental loss of data, as these project folders are all git +repositories.

File Structure

Projects have a few conventions.

  • assets/ is where files uploaded from the editor will be uploaded to

  • src/ is where code assets can be served from

  • tests/ is where test files can be run

  • sceneName.scene.json is a scene file

  • sceneName.thumbnail.png is an auto-generated scene thumbnail file

  • xrengine.config.ts the project configuration, where client routes, database +models, feathers services and the project thumbnail can be defined

A project must also have a package.json to provide custom dependencies, and to define +the project name, project version, and Ethereal Engine version it is known to work with.

Systems imported from a scene MUST have their filename end with System.ts and be in the /src/systems folder. +This is to optimize vite's code-splitting bundling process, as each potentially dynamically +importable file will result in a new bundle with it's own copy of all of it's import dependencies.

@etherealengine/* monorepo dependencies will be symlinked and not needed, but some +package managers (such as pnpm) require these to be defined. If so, they should +be defined in peerDependencies and kept up to date with the current engine version.

Config

The ethereal engine config file has the following options:

export interface ProjectConfigInterface {
onEvent?: string
thumbnail?: string
routes?: {
[route: string]: {
component: () => Promise<{ default: (props: any) => JSX.Element }>
props?: {
[x: string]: any
exact?: boolean
}
}
}
webappInjection?: () => Promise<{ default: (props: any) => void | JSX.Element }>
worldInjection?: () => Promise<{ default: () => Promise<void> }>
services?: string
databaseSeed?: string
settings?: Array<ProjectSettingSchema>
}

Hooks

The onEvent property is a relative path string that points to a file which +must expose an object with properties as follows:

export interface ProjectEventHooks {
onInstall?: (app: Application) => Promise<any>
onLoad?: (app: Application) => Promise<any>
onUpdate?: (app: Application) => Promise<any>
onUninstall?: (app: Application) => Promise<any>
/**
* get oEmbed for active routes that match URL
* return that project's onOEmbedRequest()
* if null, return default
*/
onOEmbedRequest?: (app: Application, url: URL, currentOEmbed: OEmbed) => Promise<OEmbed | null>
}

These functions are called when the project they belong to are installed, +updated (such as scenes saved) or uninstalled respectively. This is used in the +default ethereal engine project to install the default avatars. +See /packages/projects/default-project/projectEventHooks.ts.

Thumbnail

This is a URL to a thumbnail for the project.

Routes

Routes enable users to customise the various URL paths of their website +utilising dynamic loading of modules. The key of each object represents the path +(with leading forward slash included) while the value represents a react +component object which gets wrapped in React.lazy() and a props object which +passes options into the react-dom-router Route component corresponding to the route.

Webapp Injection

Webapp injection allows logic to be run on all pages, loaded before any routes +are loaded. This will soon be extended to allow easy stylesheet injection and +other configurables of the webapp.

World Injection

World injection allows logic to be run every time a new world is created, +currently only when the engine is initialised. This is loaded on all instances +of the engine, such as a location and the editor. An example use case of this +would be registering custom scene loader and editor prefabs.

Services

The services property is a relative path that points to a file which must +return type ((app: Application) => Promise<any>)[] which is run on all +instanceservers and api servers at startup. This allows users to expose custom +Feathers services, or whatever other functionality they made need.

Database Seeding

The databaseSeed property is a relative path that points to a file which must +return type ServicesSeedConfig from ../packages/common/src/interfaces/ServicesSeedConfig.ts +which is run when the database seeder is run.

i18n

Internationalization can be added using the pattern ./i18n/<language>/<namespace>.json. An example of the format can be found in the base i18n files.

+ + + + \ No newline at end of file diff --git a/es/docs/creator/development/state_management/index.html b/es/docs/creator/development/state_management/index.html new file mode 100644 index 000000000000..003e0bf21750 --- /dev/null +++ b/es/docs/creator/development/state_management/index.html @@ -0,0 +1,16 @@ + + + + + +State Management | etherealengine + + + + +
+

State Management

All of Ethereal Engine's state management uses hookstate and react. Together, these tools give reactive, declarative, and controlled state management across any scope.

Scoped State

Scoped state can be defined using the useHookstate hook - this is vanilla hookstate, and is useful for state that is only used in a single component, or state that is only used in a single component tree.

import { useHookstate } from '@hookstate/core'

const MyComponent = () => {
const state = useHookstate({
count: 0
})
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => state.count.set(state.count.get() + 1)}>Increment</button>
</div>
)
}

Global State

Global state definitions are wrapped in a 'store' which allows for automatic creation and cleanup as needed. This API as well as the underlying hookstate API can be imported from @etherealengine/hyperflux.

MyState.ts
import { defineState } from '@etherealengine/hyperflux'

const MyState = defineState({
name: 'MyState',
initial: {
count: 0
}
})

Global state will be registered to the engine instance once it has been called with getState or getMutableState. This will cause the state to be created if it does not exist, and will be cleaned up when the engine instance is destroyed.

It's proxy can be accessed with Engine.instance.store.stateMap.MyState where MyState is the name of the state.

When accessing the state, getState returns the underlying object typed as readonly. This is useful for reading state values, but should not be used to write to state.

import { getState } from '@etherealengine/hyperflux'
import { MyState } from './MyState'

const state = getState(MyState)
console.log(state.count) // 0
state.count = 1 // Error: Cannot assign to 'count' because it is a read-only property.

State can be mutated via the getMutableState function, which returns a proxy to the state, which can be used to read and write state values. The proxy is reactive, so any changes to the state will cause the component to re-render.

The proxy returned can be wrapped in hookstate's reactive hook useHookstate. This will cause the component to re-render when any state values are changed.

import { getMutableState, useHookstate } from '@etherealengine/hyperflux'
import { MyState } from './MyState'

const MyComponent = () => {
const state = useHookstate(getMutableState(MyState))
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => state.count.set(state.count.get() + 1)}>Increment</button>
</div>
)
}
+ + + + \ No newline at end of file diff --git a/es/docs/creator/importing_assets/index.html b/es/docs/creator/importing_assets/index.html new file mode 100644 index 000000000000..14c3c6995c7e --- /dev/null +++ b/es/docs/creator/importing_assets/index.html @@ -0,0 +1,18 @@ + + + + + +Asset Import Pipeline | etherealengine + + + + +
+

Asset Import Pipeline

Omniverse

Unity

Unreal

Blender

WARNING: This page is out of date

The simplest pipeline uses Blender & the Studio's inbuilt transformation tool.

Scenes that contain colliders should have these colliders exported separately. +Visible meshes should not have collider metadata, instead a copy should be created.

The process of moving from Blender to Ethereal Engine looks like the following:

  1. Blend file is the source of truth
  2. Export visible meshes from from blend file
  3. Export collider meshes from blend file with Custom Properties
  4. Import to editor
  5. Optimize visible glb with transformation tool
  6. Use final transformed visible glb & collider glb for live scene

Collider Metadata

All fixed colliders should be a child of a separate root hierarchy.

The root object of the collider hiearchy must have xrengine.collider.bodyType: Fixed +Each collider must be a child of the root object with shapeType: <shape>

The currently supported shapes are as follows:

  • Cuboid
  • Ball
  • Capsule
  • Cylinder
  • ConvexPolyhedron
  • TriMesh

Other supported metadata for each collider is:

  • friction: number
  • restitution number
  • collisionLayer: number
  • collisionMask: number
  • isTrigger: number
+ + + + \ No newline at end of file diff --git a/es/docs/creator/index.html b/es/docs/creator/index.html new file mode 100644 index 000000000000..8e7c68d8da9a --- /dev/null +++ b/es/docs/creator/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal for Creators | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/creator/studio/index.html b/es/docs/creator/studio/index.html new file mode 100644 index 000000000000..1e670a83e77d --- /dev/null +++ b/es/docs/creator/studio/index.html @@ -0,0 +1,194 @@ + + + + + +Studio Overview | etherealengine + + + + +
+

Studio Overview

Ethereal Engine Studio +UI Overview +image6

1: Toolbar

2: Scene and File Directory

3: Preview

4: Viewport

5: Hierarchy, Material Library, Node Graph

6: Properties

7: Assembly Menu

8: User Profile


1 Toolbar

1. File Menu

Create new scenes, import files, and save or export existing scenes.

2: Advanced

Toggle advanced options on Model or Avatar components. +Add and remove components in the Properties tab

3. Active Instances

Active Instances shown here

4. Transform Gizmo: Scale, Rotate, Move

[ Y ] Scale +[ R ] Rotate +[ T ] Move

  1. World Space or Object Space Transform - toggle to world or object +Sets your transform control to be oriented to the object(selection) or world +World space relates to the entire scene’s orientation +Object space (your selection) relates to transforms made to a specific object in relationship to the world space

[ Z ] Toggle World space or Object(Selection) space

  1. Toggle Transform Pivot - modes: Selection, Center, Bottom, or Origin +To use, shift select objects, enter transform mode (Y, R, T), choose pivot type: +Selection:the center pivot of the final asset you selected in the sequence +Center: a pivot that sits at an equal distance between all selections +Bottom: pivot that sits equally between all selections and at the bottom of your final selection in the sequence +Origin: sets pivot mode to the world origin (0,0,0) +*it is recommended to use the Toggle Transform in conjunction with the World/Object Space transforms

[ X ] Toggle between Selection, Center, or Bottom +[ E ] incrementally rotate around the Y axis, adopts the selected snapping degree value

  1. Grid Snapping (toggle) +Transform objects by a unit of measurement [.1 meters, .125 meters, 1 meter, 4 meters, etc] +Rotate objects by a specific degrees [5o,10o, 20o, 90o, etc]

[ C ] Toggle Snap Mode +[ E ] incrementally rotate around the Y axis, adopts the selected snapping degree value

  1. Grid Visibility (toggle) +Set grid spacing by meters
  1. Render Mode +How you view materials in the Engine +(Unlit, Lit, Shadows, Wireframe, Normals)
  1. Preview Scene +Spawns you into the scene
  1. Status (toggle)

Show stats about the scene and gives you a clue as to how optimized your scene is +Memory: Geometries, Textures +Render: FPS, Frame Time, Calls(drawcalls), Triangles, Points, Lines

  1. Helpers (toggle) +View hidden information about your scene, ie: colliders
  1. Node Helpers (toggle) +Helper geometry that helps components have visibility in the scene when inactive
  1. Take A Screenshot +Takes a screenshot of your scene at the current view

#2 Scene and File Directory

Project Files +Contains all files associated with your project. +.json files and various other file types in this menu are your project files and will show up automatically when you create a new scene.

Assets folder +Contains all assets you can import into your scene. When you use the Toolbar: File Menu to import files, they are delivered directly to the assets folder. To populate your scene simply drag them from the assets directly to your hierarchy. +Tip: Import may create a transform offset +When some assets are loaded they automatically show up in the scene in the hierarchy and sometimes at an offset. Simply delete them from the hierarchy and re-drag them from your assets folder into your scene hierarchy to have them be set at home (0,0,0)

#3 The Preview Panel +The preview panel allows you to preview certain files, currently supporting image, video and audio files

#4 Viewport +The view of all things active inside your scene. +Objects have the typical navigation controls +X = red +Y = green +Z = blue

#5 Hierarchy & Material Library +Hierarchy +The scene Hierarchy contains all element currently in your scene (assets, lighting, items from the tool menu, etc) +Material Library +Location of an assets materials and where you can select and edit them

#6 Properties +Where you can access and edit detailed information about objects in your scene. +Select an object in the Hierarchy to view its Properties. This panel supports editing and adding actions to objects, ie: keying transforms, turning on animation tracks, looping motion, and adding components to objects

Model URL +Shows the location of an object in your scene hierarchy

Using the Advanced Tab (toolbar) +By activating the advanced tab from the toolbar you are able to add specific components to assets in your scene adding data to the entity. +Explode objects that are imported as a collapsed group

Types of Components

#7 Assembly Menu

Files +Model +Creates objects in the hierarchy. Drag a model from the assets folder into the URL box or drag assets directly from project files into the hierarchy +Volumetric +Import volumetric files. Accepts DRCS, UVOL, or Manifest Files, links to cloud hosting +Video +2D plane accepts .mp4 .mkv .avi +Audio +Import audio clips, .mp3, .flac, .ogg, .wav, .m4a

Scene Composition +Ground Plane +Create collision ground plane +Group +Collection of models or assets +Asset Prefab +Create prefabs from groups or objects that are saved to the assets folder. Saving requires specific naming: 'assetName'.xre.gltf +Collider +Creates a collision ball, cuboid, capsule, or cylinder to be manually placement

Interaction +Spawn Point +A point where people will appear when they enter your scene +Portal +A portal to teleport a player to a port in a different location

Lights +Hemisphere Light +A light which illuminates the scene from directly overhead +Point Light +A light which emits in all directions from a single point +Directional Light +Creates a light that emits evenly in a single direction +Ambient Light +A combination of direct and indirect light, provides general lighting to all assets +Spot Light +Creates a light that shines in a specific direction

Scripting +Inserts code into the scene by creating a new Entity Component System based on the provided .ts file

FX +Ocean +Cube body of water +Particle Emitter +Creates a particle emitter +Cloud +Sprite based cloud volume +Water +Creates a circular water surface with ripple effect +Spline +Create and customize curves

Misc +E-commerce shop +Create a shop, choose product from dropdown, click select product, click away, click back, select product item(.glb), select variant, select product, click away, click back, object will populate scene

#8 User Profile
+Your Ethereal Engine account settings and linked account information

The settings wheel icon allows you to turn up your scene resolution. +If you notice the scene looks blurry, go to the Graphics tab inside Settings and turn the Resolution tab all the way up.

Create a Project +Import Assets +You can use the File menu to import assets or you can drag and drop them into the assets folder, when clicking and dragging notice a slight change in the color of the Engine, this signifies the engine is ready to ingest your file. +Importing assets immediately creates them in the scene at an arbitrary location when imported via the viewport. It is recommended to delete that import and drag an asset directly from project files into the hierarchy to easily zero out your transforms. +Ethereal Engine accept the following file types

3D Models .glb, .gltf +Images .png, .tiff, .jpeg +Volumetric DRCS, UVOL, Manifest Files on the Cloud +Videos .mp4m, .mkv, .avi +Audio .mp3, .mpeg, .m4a +Save Project +In the File menu, click the save or save as button to save your scene +Some projects require time to save so don't exit this window until a few minutes have passed +Edit Materials +Ethereal Engine supports a PBR workflow and Vertex Colors +PBR Workflow: +Diffuse or Base Color Map +Metalness Map +Roughness Map +Normal Map +Ambient Occlusion (AO) Map +*each of these loaded will represent one draw call, only use maps you absolutely need. You can drop the diffuse map and use our built in RGB color selector to save scene space.

Your asset materials are visible in the order below under the Material Library tab +Material Library

Asset Name +material name +material name +material name

Material Types: +MeshBasicMaterial +This material is not affected by lights. +https://threejs.org/docs/?q=meshba#api/en/materials/MeshBasicMaterial

MeshStandardMaterial +A standard physically based material, using Metallic-Roughness workflow. +https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial

MeshMatcapMaterial +MeshMatcapMaterial is defined by a MatCap (or Lit Sphere) texture, which encodes the material color and shading. +MeshPhysicalMaterial +An extension of the MeshStandardMaterial, providing more advanced physically-based rendering +(added properties include: Clearcoat, Physically-based transparency, Advanced reflectivity, and Sheen) +MeshLambertMaterial +A material for non-shiny surfaces, without specular highlights. +MeshPhongMaterial +A material for shiny surfaces with specular highlights. +MeshToonMaterial +A material implementing toon shading. +ShaderMaterial +https://threejs.org/docs/?q=shadermat#api/en/materials/ShaderMaterial +ShadowMaterial +https://threejs.org/docs/?q=shadow#api/en/materials/ShadowMaterial

Saving Changes +Anytime you make a change to a model, you need to save your change. +This includes edits to the Position, Rotation, Scale, Normals, UVs, Materials and Attributes. +After making your edit, go to the hierarchy and re-select your asset, in the Properties tab, scroll to the bottom and click the Save Changes button. If you want to Save As, in the url just above the Save Changes button, you can manually edit the name at the end of the url and click Save Changes. You can find the new version of your .glbl in the assets folder.

Tip: Convert .gltfs or .usdz to .glb format in the engine using this method +Compression +The in-engine compression menu is available when you select the model you want to run compression on from the Hierarchy. Scrolling down inside of the Properties panel you can expand the Model Transform Properties Menu. +There are three menus, gltF-Transform, Delete Attributes, Bake To Vertices.

gltF-Compression: +Runs compression on the models geometry and image textures. Default settings work well for most models. +The Image Format menu allows you to either choose JPG, KTX2, or PNG for the image’s compression format. +The Max Texture Size denotes the pixel scale of your image. Default settings downsize the textures to 1024 pixels x 1024 pixels +Press Optimize to run the compression

Delete Attributes: +Models occasionally are imported with an excess of attributes taking up unwanted space, to delete the extra, unnecessary data list the attributes here with a space in between each attribute listed

Bake To Vertices: +This tool bakes your texture to vertex color. By doing this we can eliminate the need for loading heavy images on some models. Vertex Baking transfers your PBR maps to the vertex of your model. We currently support diffuse, lightMap and emissive. +*this method is for models that have a simple texture with either a single color or few details

Animations in Objects +Avatars +To turn on the animations of an imported model you would like to use as an avatar, in the Loop Animation tab you can select the animation track you wish to activate, “mixamo.com”. +Loop Animations: loop the motion tracks available on your avatar +Checking ‘Is Avatar’ allows you to use the animations built into the engine on your Avatar.

Animated Geometry +Loop Animations: loop the motion tracks available on your model

Skybox/Cubemap +The Skybox Button from the Tools Panel allows you to create a Skybox for your scene. +You can choose between Color, Skybox, Cubemap, and Equirectangular +Color: basic color as the sky +Skybox: cubemap that surrounds your scene giving the look of being in an environment +Equirectangular: sphere that surrounds your scene giving the look of being in an environment, recommended sources for equirectangular images are hdrihaven.com or

Tip: HdriHaven has great free HDRI Resources

Importing individual models (.glb/.gltf & .usdz) +Import your model via the File Menu or drag and drop into the Viewport (when viewport changes color it is ready to ingest the file) +With the model in your Hierarchy, select it and scroll down in its Properties tab. +Re-name to your desired description with a .glb or .gltf extension. You can find your saved model in your Assets tab in the Project Files directory +scene should be determined by what your scene is composed of. Successful optimization is achieved by leveraging the appropriate use of detail per model. +Converting Models to .glb (recommended) +Convert .gltf to a .glb (in browser) +Recommended to convert .gltf into .glbs for easier importing +https://glb-packer.glitch.me/ +https://cartmagician.com/tools/3d-to-AR-converter (paid) +Convert .fbx to .glb (app) +https://github.com/facebookincubator/FBX2glTF +Convert .usd to .gltf (in browser) +https://products.groupdocs.app/conversion/usd-to-gltf

Using SampleStandardMaterial to enhance projects +Custom settings for Glass, Plastic, Glow & Metal are provided below

For the MeshStandardMaterial +(re-create values below to simulate materials on your geometry) +https://threejs.org/docs/?q=meshstan#api/en/materials/MeshStandardMaterial

Glass Plastic Glow Metal

Tip: Exporting assets for basic materials +It is not required to have a texture map on all assets in 3D and it is recommended to use Standard Materials as often as possible. We recommended using basic materials for all basic metal, glass, emissive, and plastic assets (follow the sample material set-up above). You must denote which assets will have Standard Materials before you import your .glb to the engine. It is recommended to simply drag a native material from your chosen DCC or game engine prior to export, correctly name the basic material before exporting the .glb. Names given before import are the names the engine will inherit.

Saving Your Project

Save As or Save Scene can be found in the File Menu. +Allow the Engine a few minutes to save your file. +Tip: Change the view to create a thumbnail +You will be asked to create a thumbnail on Save which takes a screenshot from the current viewport view. Move your viewport to look at the desired view for your thumbnail before you click Save.

+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/debugging/index.html b/es/docs/creator/testing/debugging/index.html new file mode 100644 index 000000000000..7afcc711357c --- /dev/null +++ b/es/docs/creator/testing/debugging/index.html @@ -0,0 +1,16 @@ + + + + + +Debugging | etherealengine + + + + +
+

Debugging

This section covers different techniques for debugging the source code.

Basic Debugging

This config can be used to debug instance server & backend server code. Navigate to 'Run & Debug' tab of vscode.

  1. Add a breakpoint to desired line of code.

  2. Select 'Debug Dev' from debug config dropdown.

  3. Hit the run/play button to start debugging.

  4. Breakpoint will be hit as the code executes that line of code.

Below image further elaborates this.

Basic Debug Image

+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/debugging_deployed_instanceservers/index.html b/es/docs/creator/testing/debugging_deployed_instanceservers/index.html new file mode 100644 index 000000000000..8668fcd6cad4 --- /dev/null +++ b/es/docs/creator/testing/debugging_deployed_instanceservers/index.html @@ -0,0 +1,32 @@ + + + + + +Debugging Deployed Instanceservers (and other Kubernetes pods) | etherealengine + + + + +
+

Debugging Deployed Instanceservers (and other Kubernetes pods)

Because of the nature of Kubernetes, logs of fatal errors on instanceserver or API pods can sometimes disappear +before one has a chance to view them, as the pods that they were on are deleted, along with their logs.

One way to catch these errors is to tail the logs of existing pods from a local machine and then trigger the error. +The tail of the logs will persist in your terminal even after the pod has been deleted.

You should already have kubectl set up and pointing to your cluster, but if not, do so. +(see here for links to do that) +Make sure you don't have a browser tab with the offending location(s) open already, as you want to be tailing +the logs before the instance starts.

Next, run kubectl get gs. If the cluster is fully installed, this will get all of the running instanceserver +pods (kubectl get pods will get all pods, if you need to find the names of API pods, etc.) +Select the Name of a pod and copy it (in Linux, highlight it and press CTRL+SHIFT+C), then run +kubectl logs <pod_name> -c <RELEASE_NAME>-instanceserver -f, +e.g. kubectl logs prod-instanceserver-vhwh2-9vqrv -c prod-instanceserver -f. It should output something like this for +and instanceserver pod:

> @etherealengine/instanceserver@1.3.0 start
> cross-env APP_ENV=production ts-node --swc src/index.ts

👾 bitECS - resizing all data stores from 100000 to 5000
Powered by three.quarks. https://quarks.art/
[hyperflux:Action] Added topic default
[hyperflux:State] registerState SceneState
[hyperflux:Action] Added Receptor EngineEventReceptor
[hyperflux:State] registerState EngineState
[hyperflux:State] registerState ServerState
Tue, 11 Jul 2023 00:38:50 GMT koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md at ../../node_modules/@feathersjs/koa/lib/index.js:52:27
[00:38:50.631] INFO: Starting app.
component: "server-core:sequelize"
[hyperflux:State] registerState NetworkState
[00:38:50.645] INFO: Starting app.
component: "server-core:mysql"
[00:38:50.900] INFO: registered kickCreatedListener
component: "instanceserver:channels"
[00:38:50.901] INFO: Starting instanceserver with NO HTTPS on 3031, if you meant to use HTTPS try 'sudo bash generate-certs'
component: "instanceserver"
[00:38:51.036] INFO: Feathers-sync started.
component: "server-core"
[00:38:51.634] INFO: Server Ready
component: "server-core:sequelize"

Since the instanceserver pod that is picked to handle a given world or media instance is random, you'll want to +open a few more tabs in your terminal and repeat the above kubectl logs command, substituting a different +instanceserver pod name in each tab, so that you're tailing all of the current pods. Then go to the location that is +displaying problematic behavior, or otherwise trigger the action that is causing problems, and you should see the error +in one of the terminals. If it's a fatal error, the logging will end with the pod, but the logs will stay in that terminal.

Note that if you want to log further errors, you may need to get the names of the new pods that are spun up to replace +the ones that crashed by running kubectl get gs or kubectl get pods again, and then using the new pods' names in +kubectl logs commands.

+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/debugging_device_wsl/index.html b/es/docs/creator/testing/debugging_device_wsl/index.html new file mode 100644 index 000000000000..55207900705f --- /dev/null +++ b/es/docs/creator/testing/debugging_device_wsl/index.html @@ -0,0 +1,21 @@ + + + + + +Debugging Engine in WSL on Phone/Headset | etherealengine + + + + +
+

Debugging Engine in WSL on Phone/Headset

This section covers testing/debugging on phone/headset when engine stack hosted in WSL2 Ubuntu on Windows 11.

  1. Ensure that your .env.local and database entries points to localhost.

  2. Open a location i.e. https://localhost:3000/location/apartment through Windows 11 chrome. It should work fine.

  3. Connect your device (currently tested on Samsung S22 Ultra) with PC and enabled USB debugging and access prompts as mentioned on https://developer.chrome.com/docs/devtools/remote-debugging/

  4. Once your device is connected, then you can see your device's browser tabs in PC's Chrome as show in below image. chrome://inspect/#devices +Device connected to PC Chrome

  5. Make sure the check boxes marked in below are checked. +Remote Devtool Options

  6. Click on "Port forwarding" button and ensure you have entries as shown in below image. Also make sure to check the port forwarding checkbox in that modal. +Port Forwarding Options

  7. Once this is done and you have Port forwardings having green circles before them which means forwarding is working as shown in below image. +Port Forwarding Enabled

  8. Navigate to https://localhost:3000/location/apartment in your device's browser.

  9. On your PC you can inspect this and allow if you face any certificate errors as shown in below image. +Remote Debugging

+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/index.html b/es/docs/creator/testing/index.html new file mode 100644 index 000000000000..822cc202e5ee --- /dev/null +++ b/es/docs/creator/testing/index.html @@ -0,0 +1,22 @@ + + + + + +Testing | etherealengine + + + + +
+

Testing

Automated testing is a cornerstone to successful software development. Tests are +not just to ensure that your application is working as intended, they are also +to ensure that existing features aren't broken by any newly introduced features +or code, aka regression bugs. The latter tends to hold more value, as it +makes the software sturdy and less prone to these types of bugs during active +development of a project. Regression bugs will quickly stall the development of +a project at a certain level of complexity, effectively preventing progress.

SMTP Testing

https://mailtrap.io/inboxes

Add credentials in .env.local

SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=2525
SMTP_USER=<mailtrap-user>
SMTP_PASS=<mailtrap-password>

Unit tests

Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:

const add2 = x => x + 2

it('should add 2 to a given number', () => {
strictEqual(add2(1), 3)
})

Integration tests

Integration tests focus on testing bundles of code units. A composition of functions, for example:

const addTwo = x => x + 2
const multThree = x => x * 3
const halve = x => x / 2

const algorithm = x => {
x = addTwo(x)
x = multThree(x)
x = halve(x)
return x
}

it('should apply the entire algorithm correctly', () => {
strictEqual(algorithm(4), 9)
})

Unit vs Integration Tests (source)

Unit TestingIntegration Testing
In unit testing each module of the software is tested separately.In integration testing all modules of the the software are tested combined.
In unit testing the tester knows the internal design of the software.In integration testing the tester doesn't know the internal design of the software.
Unit testing is performed first of all testing processes.Integration testing is performed after unit testing, and before system/end-to-end tests.
Unit testing is a white box testing.Integration testing is a black box testing.
Unit testing is performed by the developer.Integration testing is performed by the tester.
Detection of defects in unit testing is easy.Detection of defects in integration testing is difficult.
It tests parts of the project without waiting for others to be completed.It tests only after the completion of all parts.
Unit testing is less costly.Integration testing is more costly.

System tests

System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test).

End-to-end tests

End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow).

System vs End-to-end Tests (source)

System TestingEnd-to-end Testing
In system testing, whole software or application is tested at a time.In end-to-end testing, behavioral flow of the software is tested.
System testing only tests the specific software system.It tests the software system and the connected systems both.
The functionality of the software is tested.Flow from end-to-end is tested.
It validates the software system as per standards and specifications.It validated all the interfaces of the software.
Knowledge of interconnected systems is not required.Knowledge about interconnected systems is required.
It is carried out once integration testing is performed.It is performed after the system testing.
It is performed both manually and automated.It is generally performed manually.
It is the super set of end-to-end testing.It is considered as subset of the system testing.

White-box vs Black-box testing

Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing.

Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing.

The Testing Pyramid

A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution.

70% Unit tests

20% Integration tests

10% End-to-end tests

        /```\
/ E2E \
/_______\
/ \
/Integration\
/_____________\
/ \
/ Unit \
/___________________\
+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/reasonable_code/index.html b/es/docs/creator/testing/reasonable_code/index.html new file mode 100644 index 000000000000..23c2c464539d --- /dev/null +++ b/es/docs/creator/testing/reasonable_code/index.html @@ -0,0 +1,16 @@ + + + + + +Writing Reasonable & Testable Code | etherealengine + + + + +
+

Writing Reasonable & Testable Code

Writing tests for code is one thing, but writing testable code is another! Testable code comes from abstracting control flows and operations on data with functions in order to avoid side effects and reduce, or at least have better control over, the mutation of state in your application.

In the functional programming (FP) paradigm, pure functions are functions which do not mutate any existing state of any scope. Since we are not in a fully functional paradigm, a focus on these qualities of functions can be priceless: stateless functions with referential transparency.

Stateless means that the function itself has no memory of the past. Referential transparency means that the function is only operating on the parameters, and nothing else (no global state access, etc).

These types of functions may (arguably) mutate parameter state, but may only operate on the given parameters. State residing outside of the scope of a stateless function should never be depended on or mutated. This will ensure that the function holds no inherent state of its own, and therefore will exhibit the behavior of being referentially transparent and idempotent.

Idempotency is a quality of any function which can be executed several times without changing the output for a specific input. Idempotent functions can be thought of as mappings from one input to one output.

All of this combined makes functions extremely simple to reason about, very reusable, and easy to test! Three gulls, one scone.

Example

Here is an example of a function that does not exhibit referential transparency, nor is it stateless:

let y = 3
const someFunction = x => {
x += y
y++
return x
}

someFunction(3) // => 6
someFunction(3) // => 7
someFunction(3) // => 8

This function is also not idempotent. Same input, different output! Not good for reasonable code, difficult to predict.

Written as a stateless, idempotent function with referential transparency:

const someFunction = (data, x) => {
x += data.y
data.y++
return x
}

someFunction({ y: 3 }, 3) // => 6
someFunction({ y: 3 }, 3) // => 6
someFunction({ y: 3 }, 3) // => 6

The newly written function now holds no inherent state of its own and does not operate on any data that was not passed into the function as explicit arguments. It is also idempotent: same input, same output! Very reasonable and easy to predict.

Code Composition / Decomposition

We must now capture the process of decomposing a program into smaller pieces that are more reusable, more reliable, and easier to understand. Then we can combine each individual piece to form an entire program that is easier to reason about as a whole. FP tends to follow this fundamental principle.

FP falls under the umbrella of declarative programming paradigms: it expresses a set of operations without revealing how they’re implemented or how data flows through them. Unlike imperative programming, declarative programming separates program description from evaluation. It focuses on the use of expressions to describe what the logic of a program is without necessarily specifying its control flow or state change.

These two paradigms can be utilized to form powerful and extremely testable functions and compositions which support a sturdy codebase. Write functions imperatively, then compose them together declaratively!

Example

Using the previous unit/integration test examples, lets see what the algorithm would look like if written imperatively:

const algorithm = x => {
// first, add two
x += 2
// then, multiply by three
x *= 3
// finally, divide by two
x /= 2
return x
}

Rewritten declaratively, as demostrated before but with a newly introduced pipe function (a standard function in FP):

const addTwo = x => x + 2
const multThree = x => x * 3
const halve = x => x / 2

const algorithm = pipe(addTwo, multThree, halve)

algorithm(4) // => 9

As you can see, the imperative function has no reusable parts, but the declarative version does! This is a simple example, but in larger-scale functions and systems this simple distinction can be a powerful tool in writing reasonable, testable, and reusable code. Bonus: the code is self documenting. No need for comments here. Just pure, self-descriptive functions!

+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/test_driven_development/index.html b/es/docs/creator/testing/test_driven_development/index.html new file mode 100644 index 000000000000..fd8476b1ea37 --- /dev/null +++ b/es/docs/creator/testing/test_driven_development/index.html @@ -0,0 +1,16 @@ + + + + + +Writing Good Tests | etherealengine + + + + +
+

Writing Good Tests

Now that our code has been thoughtfully organized into stateless functions we can easily put them to the test with three simple steps:

  1. Mock
  2. Run
  3. Assert

First, mock up data for the input parameters.

Then, run the function with the input data to produce an output.

Finally, assert that the output is correct.

Test-Driven Development (source)

Test-driven development (TDD) is a software development process relying on software requirements being converted to test cases before software is fully developed, and tracking all software development by repeatedly testing the software against all test cases. This is as opposed to software being developed first and test cases created later.

This methodology is extremely useful and productive, because it means that your code will always have test coverage. Not only that, but you can save time by ensuring that the feature is working simply by virtue of the tests passing, instead of having to run the entire software to see whether or not the feature or module in question is functioning correctly.

The following sequence is based on the book Test-Driven Development by Example:

  1. Add a test

    The adding of a new feature begins by writing a test that passes if and only if the feature's specifications are met. The developer can discover these specifications by asking about use cases and user stories. A key benefit of test-driven development is that it makes the developer focus on requirements before writing code. This is in contrast with the usual practice, where unit tests are only written after code.

  2. Run all tests. The new test should fail for expected reasons

    This shows that new code is actually needed for the desired feature. It validates that the test harness is working correctly. It rules out the possibility that the new test is flawed and will always pass.

  3. Write the simplest code that passes the new test

    Inelegant or hard code is acceptable, as long as it passes the test. The code will be honed anyway in Step 5. No code should be added beyond the tested functionality.

  4. All tests should now pass

    If any fail, the new code must be revised until they pass. This ensures the new code meets the test requirements and does not break existing features.

  5. Refactor as needed, using tests after each refactor to ensure that functionality is preserved

    Code is refactored for readability and maintainability. In particular, hard-coded test data should be removed. Running the test suite after each refactor helps ensure that no existing functionality is broken.

    Examples of refactoring:

    • moving code to where it most logically belongs
    • removing duplicate code
    • making names self-documenting
    • splitting methods into smaller pieces
    • re-arranging inheritance hierarchies

The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply undo or revert rather than debug excessively. When using external libraries, it is important not to write tests that are so small as to effectively test merely the library itself, unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development.

Antipatterns

Practices to avoid, or "anti-patterns"

  • Having test cases depend on system state manipulated from previously executed test cases (i.e., you should always start a unit test from a known and pre-configured state).
  • Dependencies between test cases. A test suite where test cases are dependent upon each other is brittle and complex. Execution order should not be presumed. Basic refactoring of the initial test cases or structure of the UUT causes a spiral of increasingly pervasive impacts in associated tests.
  • Interdependent tests. Interdependent tests can cause cascading false negatives. A failure in an early test case breaks a later test case even if no actual fault exists in the UUT, increasing defect analysis and debug efforts.
  • Testing precise execution behavior timing or performance.
  • Building "all-knowing oracles". An oracle that inspects more than necessary is more expensive and brittle over time. This very common error is dangerous because it causes a subtle but pervasive time sink across the complex project.
  • Testing implementation details.
  • Slow running tests.
+ + + + \ No newline at end of file diff --git a/es/docs/creator/testing/testing_intro/index.html b/es/docs/creator/testing/testing_intro/index.html new file mode 100644 index 000000000000..fa5357368145 --- /dev/null +++ b/es/docs/creator/testing/testing_intro/index.html @@ -0,0 +1,22 @@ + + + + + +Testing Basics | etherealengine + + + + +
+

Testing Basics

Testing

Automated testing is a cornerstone to successful software development. Tests are +not just to ensure that your application is working as intended, they are also +to ensure that existing features aren't broken by any newly introduced features +or code, aka regression bugs. The latter tends to hold more value, as it +makes the software sturdy and less prone to these types of bugs during active +development of a project. Regression bugs will quickly stall the development of +a project at a certain level of complexity, effectively preventing progress.

SMTP Testing

https://mailtrap.io/inboxes

Add credentials in .env.local

SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=2525
SMTP_USER=<mailtrap-user>
SMTP_PASS=<mailtrap-password>

Unit tests

Unit tests focus on testing small pieces of code, usually just a single function, which only does one specific thing:

const add2 = x => x + 2

it('should add 2 to a given number', () => {
strictEqual(add2(1), 3)
})

Integration tests

Integration tests focus on testing bundles of code units. A composition of functions, for example:

const addTwo = x => x + 2
const multThree = x => x * 3
const halve = x => x / 2

const algorithm = x => {
x = addTwo(x)
x = multThree(x)
x = halve(x)
return x
}

it('should apply the entire algorithm correctly', () => {
strictEqual(algorithm(4), 9)
})

Unit vs Integration Tests (source)

Unit TestingIntegration Testing
In unit testing each module of the software is tested separately.In integration testing all modules of the the software are tested combined.
In unit testing the tester knows the internal design of the software.In integration testing the tester doesn't know the internal design of the software.
Unit testing is performed first of all testing processes.Integration testing is performed after unit testing, and before system/end-to-end tests.
Unit testing is a white box testing.Integration testing is a black box testing.
Unit testing is performed by the developer.Integration testing is performed by the tester.
Detection of defects in unit testing is easy.Detection of defects in integration testing is difficult.
It tests parts of the project without waiting for others to be completed.It tests only after the completion of all parts.
Unit testing is less costly.Integration testing is more costly.

System tests

System tests can be thought of much like unit tests, but on a grand level. These focus on ensuring that one particular system/module is functioning as expected from the outside. Using maps as an example: one may test that map API download is working correctly (one system test), that the mesh construction is working (a second system test), and that procedural mesh loading is working correctly (a third system test).

End-to-end tests

End-to-end tests can be thought of much like integration tests, but also on a grand level. These focus on flows between systems. Using the previous maps example, an end-to-end test would ensure that the entire flow of map API download, constructing meshes, and procedural loading together in one continuous flow (one whole end-to-end test for this entire flow).

System vs End-to-end Tests (source)

System TestingEnd-to-end Testing
In system testing, whole software or application is tested at a time.In end-to-end testing, behavioral flow of the software is tested.
System testing only tests the specific software system.It tests the software system and the connected systems both.
The functionality of the software is tested.Flow from end-to-end is tested.
It validates the software system as per standards and specifications.It validated all the interfaces of the software.
Knowledge of interconnected systems is not required.Knowledge about interconnected systems is required.
It is carried out once integration testing is performed.It is performed after the system testing.
It is performed both manually and automated.It is generally performed manually.
It is the super set of end-to-end testing.It is considered as subset of the system testing.

White-box vs Black-box testing

Put simply, white-box testing is when the tester knows exactly how the internals of the code are working, and knows exactly what to test and what to expect. Unit testing is white-box testing.

Black-box testing, on the other hand, is when the tester does not know anything about how the internals of the code are working, and only knows what to input and what the expected output should be. Integration, system, and end-to-end testing are all black-box testing.

The Testing Pyramid

A typical suggestion is to aim for a 70/20/10 split between these different types of tests. Although more coverage is never a bad thing, the aim should be to bolster the tests with respect to the following pyramid distribution.

70% Unit tests

20% Integration tests

10% End-to-end tests

        /```\
/ E2E \
/_______\
/ \
/Integration\
/_____________\
/ \
/ Unit \
/___________________\
+ + + + \ No newline at end of file diff --git a/es/docs/creator/tutorials/ethereal_engine/index.html b/es/docs/creator/tutorials/ethereal_engine/index.html new file mode 100644 index 000000000000..fc3ec84642f7 --- /dev/null +++ b/es/docs/creator/tutorials/ethereal_engine/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal Engine | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/creator/tutorials/ethereal_engine/unity_bridge/index.html b/es/docs/creator/tutorials/ethereal_engine/unity_bridge/index.html new file mode 100644 index 000000000000..312f9c4eea10 --- /dev/null +++ b/es/docs/creator/tutorials/ethereal_engine/unity_bridge/index.html @@ -0,0 +1,16 @@ + + + + + +Unity Bridge | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/creator/tutorials/ethereal_engine/unreal_bridge/index.html b/es/docs/creator/tutorials/ethereal_engine/unreal_bridge/index.html new file mode 100644 index 000000000000..d32d1ce4bf0d --- /dev/null +++ b/es/docs/creator/tutorials/ethereal_engine/unreal_bridge/index.html @@ -0,0 +1,18 @@ + + + + + +Unreal Bridge | etherealengine + + + + +
+

Unreal Bridge

Ethereal Engine Bridge - Unreal

https://github.com/etherealengine/XRE-Bridge-Unreal

Unreal SDK Ethereal Engine Alpha

  • User Management API
  • Server Party Matchmaker
  • Unreal Game Server Lifecycle System
  • Unreal Blueprints Ethereal Engine SDK

CMS and marketplace services coming soon

EXAMPLE https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example

Screenshot 2022-06-06 193750

Setup

This guide assumes you have a working linux dedicated server build of you game.

Preinstall Requirements

Containerization details

Configuring gameserver

register a process with ENV VARS or Unreal executable arguments

https://docs.unrealengine.com/4.26/en-US/ProductionPipelines/CommandLineArguments/

TroveServer.exe IslandLobby.uproject /Trove/Maps/Island1?game=MyGameInfo?listen -lobbygame -server 127.0.0.1
TroveServer.exe IsleOfDeath.uproject /Trove/Maps/IsleOfDeathStart?game=MyGameInfo?listen -stakedgame -server 127.0.0.1

VaREST and wrapping the Ethereal Engine Web API

knowledge required: Learn REST APIs, OpenAPI, Header based http auth, Verbs:Get/Post/etc, paylods, json

image

Targeting support for 4.26 and 4.27

Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal

https://github.com/etherealengine/XRE-Bridge-Unreal/

This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine

https://api-dev.etherealengine.com/openapi/

This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!

This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database

Screen Shot 2022-06-04 at 4 25 43 PM

Blueprints multiplayer Unreal reference

https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/

All K8 control plane systems can be access via rest calls to the local network of the gameserver, the functionality of Agones can be done via adding a node in Blueprints.

The Ethereal Engine matchmaker service exposes the default endopints for open match.

https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/01-open-match-core.yaml +https://github.com/EtherealEngine/ethereal-engine-ops/tree/master/open-match/templates/07-open-match-default-evaluator.yaml

REST API local call access docs

https://open-match.dev/site/docs/guides/access/

This is a ticketing system to be placed into a lobby group and then into a gameserver. Ethereal Engine has API call examples of this

Match User Relation

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-user/match-user.class.ts

Open Match Endpoint Reference

Match the ticket for an assignment

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket/match-ticket.class.ts

Match Gameserver Instance Relation

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-instance/match-instance.class.ts

Get a ticket for assignment to a gameserver instance

https://github.com/etherealengine/etherealengine/blob/dev/packages/server-core/src/matchmaking/match-ticket-assignment/match-ticket-assignment.class.ts

Agones Actions

unreal_bp_actions

Ethereal-Engine-Bridge-Unreal-Example

https://github.com/etherealengine/Ethereal-Engine-Bridge-Unreal-Example

Preinstall Requirements

Add Plugins

Screenshot 2022-06-06 193750

Targeting support for 4.26 and 4.27

Trial implementations on epic games unreal examples for the Ethereal Engine bridge for Unreal

https://github.com/etherealengine/XRE-Bridge-Unreal/

This bridge is wrapping OpenAPI endpoints presented by Ethereal Engine

https://api-dev.etherealengine.com/openapi/

This first requires a generated bearer token for API autorization. OAuth API app digestion with socpes is coming soon!

This can be found in the EnvVars of the Ethereal Engine cluster and in the XRE SQL Database

Screen Shot 2022-06-04 at 4 25 43 PM

Blueprints multiplayer Unreal reference

https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Networking/Blueprints/

Modeled after an updated version of

https://www.unrealengine.com/marketplace/en-US/product/multiplayer-shootout +https://docs.unrealengine.com/4.27/en-US/Basics/Projects/UIProjectConversion/

https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/BlueprintMultiplayer/

+ + + + \ No newline at end of file diff --git a/es/docs/creator/tutorials/index.html b/es/docs/creator/tutorials/index.html new file mode 100644 index 000000000000..481c91ce61a5 --- /dev/null +++ b/es/docs/creator/tutorials/index.html @@ -0,0 +1,16 @@ + + + + + +Tutorials | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/guest/index.html b/es/docs/guest/index.html new file mode 100644 index 000000000000..6bbdacfe5bb8 --- /dev/null +++ b/es/docs/guest/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal for Guests | etherealengine + + + + +
+

Ethereal for Guests

Whether you're a gamer, a shopper or just here to explore, Ethereal Engine has something for you. This section will help you get started with the basics of using Ethereal Engine.

+ + + + \ No newline at end of file diff --git a/es/docs/host/Admin_Dashboard/index.html b/es/docs/host/Admin_Dashboard/index.html new file mode 100644 index 000000000000..5bb8b6dbe353 --- /dev/null +++ b/es/docs/host/Admin_Dashboard/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal Engine Admin Panel Guide | etherealengine + + + + +
+

Ethereal Engine Admin Panel Guide

Dashboard

Usage Dashboard

Usage Time Series

Projects

Managing Projects

Project Table

Name

Version

Commit SHA

Commit Date

Update

GitHub Integration

User Access

Invalidate Cache

View Project Files

Routes

Location

Create Location

Name

Max Users

Scene

Type

Media Toggles

Make Lobby

Location Table

Instance

Patch InstanceServer

Instance Table

Instance Table Actions

Users

Create User

Name

Avatar

Scopes

Admin:Admin
Benchmarking:read/write
Bot:read/write
contentPacks:read/write
Editor:write
globalAvatars:read/write
Groups:read/write
Instance:read/write
Invite:read
Location:read/write
Party:read/write
Projects:read/write
realityPacks:read/write
Recording:read/write
Routes:read/write
Scene:read/write
Server:read/write
Settings:read/write
Static_resource:read/write
User:read/write

User Table

Invites

Avatar

Create Avatar

Avatar Name

File Source

Avatar Thumbnail

Avatar Table

Resources

Create Resource

Name

Project

File Source

Benchmarking

In work

Bots

In work

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/AWS_setup/index.html b/es/docs/host/devops_deployment/AWS_setup/index.html new file mode 100644 index 000000000000..7133bbc90ae1 --- /dev/null +++ b/es/docs/host/devops_deployment/AWS_setup/index.html @@ -0,0 +1,341 @@ + + + + + +Ethereal Engine on AWS | etherealengine + + + + +
+

Ethereal Engine on AWS

The value RELEASE_NAME referenced throughout this guide is the name of the deployment, e.g. dev or prod.

Ways of serving client files in production

There are multiple ways to serve built client files in a production environment. +You should decide how you want to serve them now, because a few later steps will be affected +by that choice, and changing your AWS configuration after everything has been set up one way +is a little tricky:

  • From client pods (separate from API pods)
  • From API pods
  • From the storage provider, such as S3/Cloudfront

Serve client files from client pods

This is the default method. The Helm charts assume that the deployment will have client pods +to serve client files, and the client ingress will point traffic to the client pods. The client +URL will be pointed to the EKS Load Balancer, and you will not need a separate client certificate.

This option gives you slightly more flexibility in scaling a deployed cluster than serving +from the API pods, since you can scale the number of API and client pods independently.

Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture +of how projects are built and served, and serving from the Storage Provider may end up being the only +allowable option.

Serve client files from API pods

This will make your builder build and serve the client service from the API pods. The Helm +chart will not have a client deployment, serviceaccount, configmap, etc., and the client +ingress will point to the API pods. The client URL will be pointed to the EKS Load Balancer, +and you will not need a separate client certificate.

To enable this, set client.serveFromApi to true in your Helm config file when you are configuring it. +This needs to be applied to both the builder deployment and the main deployment, but if you set this +before deploying anything, it will be applied to both.

This option can save you some money by requiring fewer nodes in order to host all of the +API+client pods you desire, as you do not need capacity for separate client pods. It offers +slightly less flexibility in scaling since you cannot scale the number of API and client pods +separately; more client capacity would require more API capacity, and vice versa. It also +will result in slightly longer deployment times, as the combined API+client Docker images +are larger than an API-only or client-only image (though smaller than the sum of the two +separate images), which will mean a few more seconds to download to each node.

Note that, as of this writing, this is tentatively going to be deprecated by a future re-architecture +of how projects are built and served, and serving from the Storage Provider may end up being the only +allowable option.

Serve client files from Storage Provider (S3 + Cloudfront)

This will make the client build process push all of its built files to S3 and serve them via +Cloudfront. Static resources will also be served from the client domain instead of a separate +resources domain. The client URL will be pointed to the Cloudfront distribution, not the EKS Load +Balancer; only API and instanceserver traffic will go to the EKS cluster. You will need a separate +client certificate, but you will not need a resources domain certificate.

As of this writing, only Amazon S3/Cloudfront is supported as a storage provider +in a cloud environment.

To enable this, set builder.extraEnv.SERVE_CLIENT_FROM_STORAGE_PROVIDER to true in the +Helm config file when you are configuring it. Also make sure that builder.extraEnv.STORAGE_PROVIDER is set to s3.

This option can greatly speed up the time it takes for users to fully load your worlds, +since every client file can be served from a CDN close to them, rather than +having to fetch them all from the closest physical server. It will also slightly speed up build times and deployment +times since the client build does not need to be pushed to a Docker repo (though a cache of the build will still +be pushed to speed up future builds).

Create EKS cluster with four nodegroups

You first need to set up an EKS cluster for Ethereal Engine to run on. +While this can be done via AWS' web interface, the eksctl CLI +will automatically provision more of the services you need automatically, +and is thus recommended.

First, follow these instructions +for setting up aws-cli, eksctl, and configuring aws-cli with your AWS credentials. +You should also set up kubectl and Helm, as we will be using that to install multiple codebases from Charts.

Next run the following command:

eksctl create cluster --name <name> --version <version> --region <region> --managed --nodegroup-name <name> --node-type <instance type> --nodes <target_node_number> --nodes-min <minimum_node_number> --nodes-max <maximum_node_number> --spot

This will create an EKS cluster with a managed nodegroup in the specified region, including automatically +creating subnets, making a VPC, and more. It may take up to 15 minutes to complete.

You can also use the flag --zones <zone1>,<zone2> to specify which Availability Zones the cluster +should set up in. Some regions have zones that are unavailable, but which eksctl will try to +use if --zones is not specified, leading to the setup to fail. As an example, us-west-1 (as of this +writing) does not have any resources available in us-west-1b; if you are setting up in us-west-1, +you would want to use --zones us-west-1a,us-west-1c.

Note that the region matters for almost all services in AWS. The default region is 'us-east-1', +but if you make the cluster in any other region, you'll need to make sure you're creating certs, +DNS records, etc. in the same region.

As of this writing, the API and client are configured to run on a nodegroup named 'ng-1'. +If you name it something else, be sure to change the NodeAffinity in the configuration file. This is one of four +nodegroups that will be created for various services to run on.

Make sure to increase the maximum node limit, as by default target, minimum, and maximum are +set to 2, and Ethereal Engine's setup will definitely need more than two nodes if you've configured +them to use relatively small instance types such as t3a.medium.

Enable EBS CSI Addon (if EKS version is 1.23 or later)

Follow the instructions here +to enable an EKS addon that's required for any cluster that will have Persistent Volumes, which an +Ethereal Engine deployment cluster will.

Install Cluster Autoscaler (optional)

While not necessary, it can be useful to have an autoscaler installed in the cluster to increase +the number of nodes available for pods when the cluster has high traffic and to decrease that +number when it has low traffic.

Follow these instructions +to set up the autoscaler. Any managed nodegroups created in the following steps should by default be +tagged such that the autoscaler can control them, so no further action should be required.

Note that there is some lag time on scaling up and down. It generally takes about 5 minutes from +the time that the autoscaler sees the need to add more nodes before those nodes have been spun up, +the appropriate Docker image has been installed onto them, and they are ready to be used. It takes about +15 minutes for the autoscaler to actually remove nodes that are deemed superfluous, as a hedge against +the recent high traffic picking up again.

The OIDC provider that was created in the prior step, installing the EBS CSI Addon, can be re-used in this step.

Create launch template

Go to EC2 -> Launch Templates and make a new one. Name it something like 'etherealengine-production-instanceserver'. +Most settings can be left as-is, except for the following:

  • Storage -> Add a volume, set the size to ~20GB, and for Device name select '/dev/xvda'.
  • Network Interfaces -> Add one, and under 'Auto-assign public IP' select 'Enable'

Create nodegroup for instanceservers

Go to the AWS website, then go to EKS -> Clusters -> click on the cluster you just made -> Configuration -> Compute. +You should see one managed nodegroup already there; clicking on its name will open up information +and editing, though you can't change the instance type after it's been made.

Back at the Compute tab, click on Add Node Group. Pick a name (something like ng-instanceservers-1 is recommended), +select the IAM role that was created with the cluster (it should be something like eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>), +toggle the Use Launch Template toggle and select the launch template you made in the previous step, +then click Next. On the second page, Choose the instance type(s) you'd like for the group, +set the minimum/maximum/desired scaling sizes, and hit Next (t3(a).smalls are recommended). +There may be connection issues with instanceserver instances in private subnets, so remove all of the private +subnets from the list of subnets to use, and make sure that public subnets are being used (sometimes +the workflow only selects private subnets by default). Hit Next, review everything, and click Create.

Create nodegroup for redis

Redis should get its own nodegroup to isolate it from any other changes that might be made to your cluster. +As with the instanceserver nodegroup, it's not strictly necessary, but can prevent various other things from +going down due to the redis servers getting interrupted.

Back at the Compute tab, click on Add Node Group. Pick a name (the default config in ethereal-engine-ops assumes +a name of 'ng-redis-1'), select the IAM role that was created with the cluster +(it should be something like eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>), +toggle the Use Launch Template toggle and select the launch template used to make the initial nodegroup, +then click Next. On the second page, Choose the instance type(s) you'd like for the group, +set the minimum/maximum/desired scaling sizes (you can probably get away with a single t3(a).small, but it's recommended +to have at least two nodes so that one going down doesn't kill the entire deployment from a lack of redis), and hit Next. +The default subnets should be fine, so hit Next, review everything, and click Create.

Create nodegroup for builder

The full Ethereal Engine stack needs a builder server within the cluster in order to bundle and build +Ethereal Engine projects into the codebase that will be deployed. This should run on its own nodegroup +that has a single node - only one copy of the builder should ever be running at a time, and +due to the high memory needs of building the client service, a box with >8 GB of RAM is needed.

Back at the Compute tab, click on Add Node Group. Pick a name (something like ng-dev-builder-1 is recommended) and +select the IAM role that was created with the cluster (it should be something like +eksctl-<cluster_name>-node-NodeInstanceRole-<jumble_of_characters>). You don't need to use any Launch Template +for this nodegroup. Click Next.

On the second page, you can change the Capacity Type to Spot if you want to in order to save money; the builder +service will likely not be running very often or for too long, so the odds of it getting interrupted by Spot instance +outages are low, and it can always re-build if that does happen. Set the Disk Size to 50 GB; it takes a good deal of +disk space to install and build the Ethereal Engine codebase, and the default 20 GB will almost certainly not be enough.

For Instance Types, you need to only select types that have more than 8 GB; t3a.xlarge are the cheapest that fit +this criteria. If you were to pick something with 8GB, it's highly likely that most builds would crash the node, +as Kubernetes tends to restart nodes if they get anywhere near memory capacity. +Under Node Group Scaling Configuration, set all three nodes values to 1. We only want a single copy of the builder +at any given time, and running multiple powerful boxes can get pricey. Click Next.

You can leave the subnets on the next page alone and click Next. On the last page, click Create.

Create ECR repositories for built images.

The Ethereal Engine deployment process will be building multiple Docker images, and those need to be stored somewhere. +In AWS, that somewhere is Elastic Container Registry. +You need to make those repositories in the same AWS region where the EKS cluster is running.

Go to the ECR link above and click Get Started under Create a Repository. If you're very concerned about any of your +Ethereal Engine project codebase(s) getting out, you can choose Private for Visibility Settings, but normally Public is fine. +You'll be needing to create multiple repositories for each deployment, e.g. several repos for a dev deployment, +several more for a prod deployment, etc.

Assuming you're first doing a dev deployment, name the first repo etherealengine-<RELEASE_NAME>-builder under Repository +Name, e.g. etherealengine-dev-builder. You shouldn't need to change any other settings, though if you're using a Private +repo and want to turn on Tag Immutability, that's fine. The image tags that are generated should never collide, but it +will prevent any manual overwriting of a tag. Click Create Repository.

You will need to make four more repos for each of the services that are deployed as part of the Ethereal Engine stack - +api, client, instanceserver and taskserver, which are also in the form etherealengine-<RELEASE_NAME>-<service_name>. +e.g. etherealengine-dev-api, etherealengine-dev-client, etherealengine-dev-instanceserver and etherealengine-dev-taskserver. +Everything else can be left alone for those, too.

On the repositories page, you should see both of +the repositories you made. If you don't see any, you may be on the wrong tab up top - click Private or Public to switch +between them. Also check that you're in the right AWS region. You'll see a column 'URI'. If you made public repos, +the URIs should be in the form public.ecr.aws/<identifier>/etherealengine-<RELEASE_NAME>(-builder); if you made private +repos, the URIs should be in the form <AWS_account_id>.dkr.ecr.<AWS_region>.amazonaws.com/etherealengine-<deployment>(-builder). +Take note of everything before the /etherealengine-<RELEASE_NAME> - you'll need to add that as a variable in later steps. +It will be called ECR_URL there.

Create IAM Roles for S3/SES/SNS (or a single admin role)

Ethereal Engine interfaces with several AWS services and requires credentials for these purposes. You could make +one admin role with full access to all AWS services, but we recommend making separate, scoped roles for +each individual service. To create a role, do the following:

Creating an IAM role

Go to IAM->Users, and click on the Add User button. For User Name, enter <service>-admin, e.g. S3-admin. +Check the box for Programmatic Access, the click on the Next:Permissions button. +Click on 'Attach existing policies directly'. In the Filter Policies text box, you'll want to +enter the name of the service to narrow down the policy list significantly. Then, look for the FullAccess +policy for that service and select that, and click the Next:Tags button. You don't need to tag it with +anything, just click the Next:Review button, then the Create User button.

The following screen should show Success and have the user listed. Copy the 'Access key ID' somewhere, and +also click the Show toggle under 'Secret access key' and copy that elsewhere as well. You will put these +into the Helm config file later.

IAM Roles to create

Here are the services you want to create IAM admin users for, and the associated permissions you want to +grant them:

  • S3: AmazonS3FullAccess, CloudFrontFullAccess
  • SNS: AmazonSNSFullAccess

You'll also need to create an IAM user that GitHub Actions can use to access the cluster and push/pull +Docker images from ECR. By convention, we call this user 'EKSUser', and it needs these +permissions: AmazonEKSClusterPolicy, AmazonEKSWorkerNodePolicy, AmazonEKSServicePolicy, AmazonElasticContainerRegistryPublicFullAccess, AmazonEC2ContainerRegistryFullAccess

Creating new credentials for an IAM user

If you ever lose the secret to a user, or want to make new credentials for whatever reason, go to +IAM->Users and click on that user. Click on the 'Security credentials' tab, and under 'Access keys' you +should see a button 'Create access key' and, underneath that, 0-2 existing keys with some information +about them and an 'x' on the far right to delete it. If there are two keys for that user, you +must deactivate and delete one of them before making a new one.

Click the Create button, then make sure to save the public and secret keys somewhere and put them into +the Helm config file.

Create RDS box

Ethereal Engine is backed by a SQL server. We use MariaDB in development, but it has also been run on AWS with +Aurora without issue. Most other versions of SQL should work but have not been explicitly tested.

Accessing RDS box from an external machine

By default, an RDS box is only accessible from within the VPC it's located. +If you want to be able to connect to it from outside that VPC, you'll need to either set up a bastion box +and SSH into that box, or make the RDS box publicly accessible.

Setting up a bastion box is not covered here at this time. The steps to make it public will be noted +below by Make RDS public

Create RDS instance

Go to RDS and click the Create Database button. Most options can be left at their default values. +Under Settings, give a more descriptive DB cluster identifier. The Master Username can be left as admin; +enter a Master Password and then enter it again in Confirm Password.

Under DB instance class, pick an option that best meets your pricing needs.

Under Availability and Durability, it's recommended that you leave it on the default of +making an Aurora Replica in another AZ.

Under Connectivity, make sure that it's in the VPC that was made as part of the EKS cluster.

Make RDS public +If you want to be able to access it externally, you should set Public Access to 'Yes'.

Under VPC security group, select the ones titled +eksctl-<EKS_cluster_name>-cluster-ClusterSharedNodeSecurityGroup-<random_string> and +eks-clustersg-<EKS_cluster_name>-<random_string>.

Open the top-level Additional Configuration dropdown (not the one within Connectivity). Under Database Options-> Initial Database Name, +name the default database and save this for later use in the Helm config file.

Finally, click the Create Database button at the very bottom of the page.

Make RDS Public You will need to add a Security Group to the RDS instance that allows traffic over port +3306 (or whatever port you chose to run it on). You can have this SG only let in traffic from your IP address(es) +if you want to be very secure about this, or from anywhere (0.0.0.0/0) if you're less concerned about someone +getting access.

Some values to note for dev/prod.template.values.yaml: +sql.database will be what you entered for Initial Database Name +sql.user and sql.password will be the name and password of the admin user +sql.host will be the Endpoint of the RDS instance/cluster; find this by going to RDS -> Databases, +clicking on either the lone DB identifier (if made in a single AZ) or the top-level regional cluster +identifier (if set up in a multi-AZ deployment); the look for Endpoint (single-AZ) or, if multi-AZ, +the Endpoint name that has type 'Writer instance'.

Edit security group to allow instanceserver traffic into VPC

You'll need to edit the new cluster's main security group to allow instanceserver traffic. +On the AWS web client, go to EC2 -> Security Groups. There should be three SGs that have +the node's name somewhere in their name; look for the one that is in the form +eks-cluster-sg-<cluster_name>-<random_numbers>. It should NOT end with /ControlPlaneSecurityGroup +or /ClusterSharedNodeSecurityGroup. +Click on that, then the Inbound Rules tab, then click Edit Inbound Rules.

You'll need to add two rule sets:

  • Type: Custom UDP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')
  • Type: Custom TCP; Port Range: 7000-8000; Source: Anywhere (or 'Custom 0.0.0.0/0')

Create Route 53 Hosted Zone and set up ACM certificates

Before installing Nginx to the cluster, you'll need to have all of the networking squared away. +This requires creating the necessary SSL certificates and creating some DNS records to point +various subdomains to the right place.

Purchase and register domain through Route53 (optional)

If you do not have a domain for your application already, it's easiest to register it through Route53. +Go to Route53->Domains->Registered domains, then click the 'Register Domain' button, and follow the +workflow to register a domain name.

Create Route 53 Hosted Zone

In the AWS web client, go to Route 53. Make a hosted zone for the domain you plan to use for +your setup of Ethereal Engine. You'll be coming back here later to create DNS records.

Open the Hosted zone, then click on 'Hosted zone details' to see more information. The value 'Hosted zone id' +is used in the dev/prod.values.yaml file for 'ROUTE53_HOSTED_ZONE_ID'

Point external registrar subdomains to use Route53 Nameservers (only if your domain is registered outside Route53)

If you already have a domain registered with another registrar service, you'll need to add some DNS records +in there to point the specific subdomains you'll be using to AWS' nameservers.

First, go to Route53->Hosted Zones and open the domain you'll be using by clicking on the domain name (or +highlighting the row and clicking the 'View details' button). There should be two records under Records. +Look for the one of type 'NS'; under 'Value/Route traffic to', there should be four lines that all start +with 'ns-'. These will be used shortly.

Go to your external registrar and go to the DNS records page. For each subdomain that will be in use, you +need to add four records of type 'NS'. The Name wil be the subdomain, and the Nameserver will be one of +the four lines under the 'NS'. You need a record for each of the four lines.

If you're setting up multiple deployments, e.g. both a dev and prod deployment, you'll need a set of four +NS records for each subdomain that those deployments will be behind.

Create certificates with ACM

Go to Amazon Certificate Manager. If there are no certs in that region, click on Get Started under Provision Certificates, +otherwise click on Request a Certificate.

You should select Request a Public Certificate, then select Request a Certificate. The next page +should be headed Add Domain Names. You should add both the top-level domain, such as etherealengine.org, +as well as a wildcard for all subdomains e.g. *.etherealengine.org, then click Next.

Choose DNS Validation on the next page and click Next. You can skip adding tags and just click Review, +then Confirm on the final page.

You should be sent to a page headed Validation. Click on the arrow next to each domain to open more +options. Click on the button Create Record in Route 53 to open a confirmation modal, and in that modal +click Create.

As it indicates, it can take up to 30 minutes for these domains to be validated. If you click on Complete +after triggering the record creation for each of them, you should be sent back to the Certificates page. +Opening the cert you just made will show the validation status of each domain.

If you open the details of this certificate, there should be a field 'ARN' with a value that looks +something like arn:aws:acm:<region>:<AWS account ID>:certificate/<a UUID>. Take note of this for later, +when you go to install ingress-nginx.

If you are serving client files from client or API pods

You should follow the above instructions to make a second certificate for resources.<domain>. +Note that this certificate MUST be made in us-east-1, regardless of which region everything else is +set up in; as of this writing, CloudFront can only use certificates in us-east-1.

If you are serving client files from the Storage Provider

You should follow the above instructions to make a second certificate for <RELEASE_NAME>.<domain>. +Note that this certificate MUST be made in us-east-1, regardless of which region everything else is +set up in; as of this writing, CloudFront can only use certificates in us-east-1.

Install Agones, ingress-nginx, and a copy of redis for each deployment

Now that the cluster is up and running, we can install everything onto it. +When you created the cluster with eksctl, it should have created a context pointing to +it in kubectl. Run kubectl config get-contexts to get all of the contexts it knows about; +the one with a star next to it should be named <your_AWS_username>@<cluster_name>. +If that isn't present, you'll have to edit the configuration to make the appropriate context.

You next need to add the Agones, ingress-nginx, and redis Helm charts to helm by running +helm repo add agones https://agones.dev/chart/stable, helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx, and helm repo add redis https://charts.bitnami.com/bitnami. +You should also at this time add Ethereal Engine's repo via helm repo add etherealengine https://helm.etherealengine.org.

If you ever suspect that a chart is out-of-date, run helm repo update to update all of them to the latest.

Install Agones

From the top level of this repo, run helm install -f </path/to/agones-default-values.yaml> agones agones/agones. +This says to install a service called 'agones' from the 'agones' package in the 'agones' chart, and to configure it with +agones-default-values.yaml that can be found in ethereal-engine-ops repo.

Install redis for each deployment

Each deployment of Ethereal Engine uses a redis cluster for coordinating the 'feathers-sync' library. +Each redis deployment needs to be named the same as the deployment that will use it; for an +Ethereal Engine deployment named 'dev', the corresponding redis deployment would need to be named +'dev-redis'.

Run helm install -f </path/to/redis-values.yaml> <RELEASE_NAME>-redis redis/redis to install, e.g. +helm install -f </path/to/redis-values.yaml> dev-redis redis/redis.

redis-values.yaml can be found in ethereal-engine-ops repo.

If you named the redis nodegroup something other than 'ng-redis-1', you'll have to alter the value in +redis-values.yaml in two places to your redis nodegroup name. +If you didn't create a nodegroup just for redis, you must omit the -f </path/to/redis-values.yaml>, +as that config makes redis pods run on a specific nodegroup.

Redis can be installed as part of the Ethereal Engine chart so long as the config file for the Ethereal Engine installation has 'redis.enabled' set to true. +In that case, you should skip the above step of installing redis separately. This is not recommended for production +environments, though, since upgrades to an Ethereal Engine installation will usually reboot the redis servers, +leading all of the instanceservers to crash due to their redis connections being severed.

This breaks Agones' normal behavior of keeping Allocated instanceservers running until every user has left and slowly replacing +old Ready instanceservers with new ones, maintaining an active pool of instanceservers at all times. You will encounter a period +of time where there are no active instanceservers at all, which is not recommended, and all instanceservers in use +will immediately go down.

Install ingress-nginx

This step cannot finish until the associated ACM Certificate is fully validated +Open local version of nginx-ingress-aws-values.yml file. Take note of the line +service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "<ACM Certificate ARN for SSL>" +Replace the bit in angle brackets, including the angle brackets, with the ARN of the certificate +you made for the top-level domain and all wildcarded subdomains, e.g. +service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-1:103947711118:certificate/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"

Do not commit this file with the ARN inserted; once you've completed this step, revert the file back +to the state it was committed in.

From the top level of this repo, run helm install -f </path/to/nginx-ingress-aws-values.yml> nginx ingress-nginx/ingress-nginx +This says to install a service called 'nginx' from the 'ingress-nginx' package in the 'ingress-nginx' chart, and to configure it with +a file found at nginx-ingress-aws-values.yml.

Set up Simple Email Service (optional)

If you want to enable email magiclink login, you will need to set up Simple Email Service (SES).

In the AWS web client, go to SES -> Configuration -> Verified Identities. Click Create Identity, then under 'Identity type' +select 'Domain'. Enter the top-level domain under the 'Domain' field. Finally, click the 'Create identity' button.

Create SMTP credentials

You need to create SMTP credentials in order to authorize SES. These will show up as an IAM user, +but you must go through an SES-specific process to get valid credentials; just creating an IAM user +with SESFullAccess will not work.

Go to an SES page and select 'SMTP Settings', then click the button 'Create SMTP Credentials'. +You can leave the default IAM User Name as-is; click the Create button. You should be taken to a screen +says a user has been created successfully. Click on 'Show User SMTP Security Credentials'.

You will see a Username and Password. These credentials will go into the Helm config file, under +AWS_SMTP_USER and AWS_SMTP_PASS, respectively. You must also fill in the region that you've created these credentials +in, replacing <SES_REGION> in api.extraEnv.SMTP_HOST.

Move SES out of Sandbox

By default, SES domains are in Sandbox mode, where they can only send emails to verified email addresses. +To request that the domain be moved out of Sandbox mode, go to SES->Email Sending->Sending Statistics. +Click on the button 'Edit your account details' to open the modal. Set 'Enable Production Access' to Yes, +leave Mail type on 'Transactional', then fill in the Website URL, add a Use case description (basically +just assure them that this is for account login only, not anything else), click the checkbox to agree +to their TOD, and click the button 'Submit for review'.

It may take up to a few days for them to take action. If the request is rejected, address their concerns. +Once you have been approved, email login should work for any email address.

Verifying test emails

Before you have production use for your SES domain, in order to log in you'll have to verify specific email +addresses with SES. Go to SES->Identity Management->Email Addresses. Click on the button 'Verify a New Email +Address'. Enter the address you want to test with, then click 'Verify This Email Address'. You should soon +receive an email with a link to verify it (it may go to your Spam folder). Once you've followed the link, +you can log in with that address.

Set up Simple Notification Service (optional)

If you want to enable text message-based magiclink login, you will need to set up Simple Notification Service (SNS).

In the AWS web client, go to SNS -> Topics and Create a new topic. +Give it a name, and selected 'Standard' as the type, then click Create Topic.

Set up S3 bucket for static resources and Cloudfront distribution

Various static files are stored in S3 behind a Cloudfront distribution. If you are serving the client files +from the Storage Provider, then all client files will be stored and served from these as well.

Create S3 bucket

In the AWS web client, go to S3 -> Buckets and click Create Bucket. +Name the bucket <name>-static-resources, e.g. etherealengine-static-resources, and have it be in Region us-east-1. +Under Object Ownership, select 'ACLs enabled', and under that select 'Object Writer'. +Under Block Public Access Settings For The Bucket, uncheck the checkbox Block all Public Access; +you need the bucket to be publicly accessible. +Check the box that pops up confirming that you know the contents are public. +All other settings can be left to their default values; click Create Bucket.

Open the bucket's settings and go the Permissions tab. Midway down is 'Access control list'. Edit that, and +Check the boxes for Objects:List and Bucket ACL:Read for 'Everyone (public access)'. Click the box with the +warning label that appears that says "I understand the effects of these changes on my objects and buckets", +then click Save Changes. +At the bottom of the Permissions tab is a Cross-origin Resource Sharing (CORS) box. +It should have the following settings; if not, click Edit and copy this in:

[
{
"AllowedHeaders": [],
"AllowedMethods": [
"HEAD",
"GET",
"POST"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]

Create Cloudfront distribution

In the AWS web client, go to Cloudfront -> Distributions and click on Create Distribution. +Under 'Web', click on Get Started.

Under Origin, click on the text box under Origin domain, and select the name of the S3 bucket you just made. +The Name field should be automatically populated, and should be left as whatever that value is.

Several fields in Default cache behavior will be changed.

Under Viewer -> Viewer protocol policy, select 'Redirect HTTP to HTTPS' +Under Viewer -> Allowed HTTP methods, select 'GET, HEAD, OPTIONS', and check Cache HTTP methods -> OPTIONS.

In Cache key and origin requests, leave it on Cache policy and origin request policy. +If this option is not available, see the below subsection for Legacy cache settings

For Cache policy, you will need to make a new policy, which is easily done by clicking the link Create policy +underneath the selector; this will open a new tab. Name this policy anything you want, e.g. 'Cached-on-headers', +then under Cache key settings, click on the Headers selector and select 'Include the following headers'. A new +selector should appear under that titled Add header. Click the selector, and check 'Origin', +'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away from the menu. Click the 'Create' +button to create the new policy.

Once the policy has been created, go back to the tab that you were creating the CloudFront distribution in. +Click the refresh button to the right of the Cache policy selector to fetch your new policy, then click the selector, +and your new policy should appear in the selector at the bottom of the list under the header 'Custom'. Select it.

For Origin request policy, select the option 'CORS-S3Origin'.

You should also make a custom response header policy so that files are served with the Origin-Agent-Cluster +header, which will tell most browsers to isolate resources for same-site cross-origin requests. To do that, +you will need to make a custom response header policy. Under Response headers policy, select Create Policy. +This will open a separate tab. Name this something like Origin-Agent-Cluster, then under Custom headers, +click Add header. For name, enter Origin-Agent-Cluster, and for Value, enter ?1. Then click the Create +button at the bottom.

Go back to the tab where you were creating the Cloudfront distribution. Click the refresh button to the right of +the Response headers policy selector to fetch the new policy, then click the selector, and your new policy should +appear in the selector at the bottom of the list under the header Custom. Select it.

Under Settings, you can change Price class to 'Use Only North America and Europe' to save some money. +For Alternate Domain Names, click 'Add item', then in the text box that appears, enter 'resources.<domain>', e.g. +resources.etherealengine.org, or '<RELEASE_NAME>.<domain>', e.g. dev.etherealengine.org, depending on +whether you are serving the client files from client/API pods or the Storage Provider, respectively. +Under Custom SSL Certificate, click on the selector that says 'Choose certificate', then select the +'resources.<domain>'/'<RELEASE_NAME>.<domain>' certificate you made earlier. If you are serving the client +files from the Storage Provider, under Default root object, enter client/index.html; if you are serving +the client files from client/API pods, leave this blank.

Everything else can be left at the default values, click Create Distribution.

Legacy cache settings

If for some reason Cache policy and origin request policy is not available for you, and you have to use +Legacy cache settings, the under Headers, select 'Include the following headers'. Under Add header that appears, +click on the selector titled 'Select headers', and in the menu that opens, check 'Host', 'Origin', +'Access-Control-Request-Method', and 'Access-Control-Request-Headers', then click away.

Set up DNS records

The Nginx Load Balancer must be fully set up and running before this step can be completed

In the AWS web client, go to Route 53, then go into the Hosted Zone you made earlier. +Click on Create Record. If it starts you under Quick Create Record, click the link +'Switch to Wizard'; it's not necessary, but the wizard is handy.

Under Routing Policy, leave it on Simple Routing and click Next. Then click Define Simple Record.

The first record should be for the top-level domain, e.g. etherealengine.org, so leave the Record Name +text field blank. Under Value/Route Traffic To, click on the dropdown and select +Alias to Network Load Balancer. Select the region that your cluster is in. +Where it says Choose Load Balancer, click the dropdown, and select the NLB that was created. +Leave the Record Type as 'A - Route traffic to an IPv4 address and some AWS resources', then click +Define Simple Record.

You can keep clicking Define Simple Record to make more records in one batch. When you're +done, click Create Records.

You should make the following 'A' records to the loadbalancer, substituting your domain for 'etherealengine.org':

  • etherealengine.org
  • *.etherealengine.org
  • @.etherealengine.org
  • api-dev.etherealengine.org
  • api.etherealengine.org
  • dev.etherealengine.org -- Only if serving client files from client/API pods
  • instanceserver.etherealengine.org
  • instanceserver-dev.etherealengine.org

You also need to make an 'A' record pointing 'resources.etherealengine.org' or '<RELEASE_NAME>.etheralengine.org' to the +CloudFront distribution you made earlier. +Instead of 'Alias to Network Load Balancer', select 'Alias to Cloudfront distribution', then click the text box that appears +that says 'Choose distribution'. A selector should appear with the subdomain you're routing as well as the Cloudfront +distribution's domain name, which you should click on. Then click Define simple record.

Create GitHub fork of Ethereal Engine repository.

The Ethereal Engine codebase is most easily deployed by forking it and configuring some Secrets so that the included GitHub +Actions can run the deployment for you. You can run all of the commands that the <dev/prod>-deploy action runs manually +if you so choose, and in that case, you don't need to fork the GH repo.

Go to https://github.com/etherealengine/etherealengine. In the upper right-hand corner, there's a button 'Fork'. Click that, +then click the account/organization you wish to fork it to. You should be taken to your fork in a short time.

You'll need to set several Secrets (runtime variables) for GitHub Actions. By default GitHub Actions should be fully +enabled, but you can double-check by going to Settings->Actions. Allow All Actions should be selected under Actions +Permissions.

Next click on Secrets under Settings. There should be none by default. Click on New Repository Secret near the top of +this page to make a new one. You will need to make several Secrets with the following Names and Values:

  • EKS_AWS_ACCESS_KEY -> The public Key of the EKSUser IAM user
  • AWS_REGION -> The region of your ECR repos and EKS cluster
  • EKS_AWS_SECRET -> The secret key of the EKSUser IAM user
  • CLUSTER_NAME -> The name of the EKS cluster
  • DEPLOYMENTS_ENABLED -> Set to true
  • DEV_REPO_NAME -> The base name of the dev ECR repository, e.g. etherealengine-dev (all references to the builder and service repos will append -builder/-<service> to this value)
  • DOCKER_LABEL -> This can be almost anything, but you can use lagunalabs/etherealengine
  • ECR_URL -> The root ECR_URL for your repos, i.e. everything before the /etherealengine-dev-builder, e.g. 11111111111.dkr.ecr.us-west-1.amazonaws.com or public.ecr.aws/a1b2c3d4
  • PRIVATE_ECR -> Set this to true if your ECR repos are private, if they're public you don't need to set this at all

If you go to the Actions Tab, you might see a few workflow runs with green checkmarks. If so, you'll be re-running the +dev-deploy workflow shortly; its initial run just ran a check to see if it should do a deployment based on +DEPLOYMENTS_ENABLED, and since that wasn't set to true, it didn't do anything else. Now that that's set to true, +re-running it will trigger a deployment.

If you're asked to enable actions when going to the tab, and there are no runs listed after enabling actions, then you'll have to +trigger the workflow by pushing new code to the dev branch.

Grant EKSUser access to cluster

By default, only the IAM user who set up an EKS cluster may access it. +In order to let other users access the cluster, you must apply an aws-auth configmap to the cluster +granting access to specific IAM users. A template of aws-auth-template.yml file can be found in ethereal-engine-ops repo.

You'll need to provide a few values for this file. To find <rolearn>, in AWS go to EKS->Clusters-> +<your cluster>->Compute->Select a nodegroup. In the details should be 'Node IAM Role ARN'; copy this +and replace <rolearn> in the aws-auth file. <account_id> is the ID of your AWS account; in the upper +right corner of the AWS client should be <your_username>@<abcd-1234-efgh>. The 12-character string +after the @ is the account ID. Make sure to remove the -'s from the account ID when pasting it in. +<IAM_username> is the username of the IAM user you want to give access, e.g. EKSUser.

You can add multiple users by copying the - groups: section under mapUsers, e.g.

  mapUsers: |
- groups:
- system:masters
userarn: arn:aws:iam::abcd1234efgh:user/EKSUser
username: EKSUser
- groups:
- system:masters
userarn: arn:aws:iam::acbd1234efgh:user/FSmith
username: FSmith

When the aws-auth config file is filled in, just run kubectl apply -f path/to/aws-auth.yml.

Deploy to EKS using Helm

With all of the networking set up, you can finally deploy the codebase to EKS. +There's a couple of steps to this, which will involve deploying things with most but not all of the needed +configuration values, and then letting the deployment process fill in the rest.

Fill in Helm config file with variables

Template Helm config files for dev and prod deployments can be found in configs <dev/prod>.template.values.yaml. +Before filling them in, make a copy elsewhere, call that '<dev/prod>.values.yaml', and edit that copy. +Both the builder and main deployments should use the same config file. When the builder seeds the database, +it needs a number of values that only need to be configured for the other services, so all of the values +need to be defined in one config file.

There are many fields to fill in, most marked with <>. Not all are necessary for all situations - if you're not +using social login, for instance, you don't need credentials for Github/Google/Facebook/etc.

Configuration variables of note

Here are some configuration variables that you'll probably need to change based on your specific setup

<api/instanceserver/taskserver>.extraEnv.AUTH_SECRET

This is a secret value that is used to sign the JWTs that authenticate users. +You can use any string for this value, and a randomly-generated one of sufficient length, +i.e. 32 or more characters, will suffice. If this is changed after some users have signed +in, their login credentials won't work any more.

<api/client/taskserver>.affinity.nodeAffinity

Within the sections of the config for the api, client, instanceserver, etc., is a section that looks +something like this:

  affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- ng-1

The value, ng-1 in this example, must be changed to match whatever the name of the nodegroup that +that service will be running on, e.g. if you create a nodegroup for the instanceservers called +abcd-instanceservers-5, then you'd use that value under values:

If your EKS setup created a nodegroup for you, and you want to use that for the api, client, and +task servers, make sure to change the affinity value for them to whatever EKS named the +initial nodegroup.

builder.extraEnv.PRIVATE_ECR

If you're using a private ECR repo, set this to "true" in the builder config file.

(everything).image.repository

You'll need to replace every <repository_name> with the full ECR_URL of your non-builder repos, e.g. abcd1234efgh.dkr.ecr.us-west-1.amazonaws.com/etherealengine-dev-api. +Each service has to have the proper -<service> suffix on it, e.g. -api, -client, etc.

GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET

If you plan to backup Projects you create in the editor to GitHub, or install project from GitHub, it is necessary +to set up the OAuth app that will facilitate this before the initial installation. +See this document for +more information, and enter the appropriate ID/secret in these variables.

Run Helm install

Run helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME>-builder etherealengine/etherealengine-builder +and then run helm install -f </path/to/<RELEASE_NAME>.values.yaml> <RELEASE_NAME> etherealengine/etherealengine

This will spin up the main and builder deployments using the Helm config file, <dev/prod>.values.yaml. +Neither will fully work yet, since there's no valid image in the repos yet. The GitHub +Actions and builder processes will make those images and update the deployments with the tags of the images they've built +so that they can pull down and use those images.

Kick off GitHub Actions

In GitHub, if you go to back to the Actions tab, you should see a dev-deploy action. Click on it, and you should see +a page showing its status, which should be all green checkmarks or indicators that things didn't run. In the upper +right, click Re-run all jobs. This will start it again, and now that DEPLOYMENTS_ENABLED is set to true, it should +attempt to build and deploy the builder.

(If actions were disabled at first, you'll have to merge additional code into the dev branch to get it to start the dev-deploy process)

Overview of the build process

The full build and deployment process works like this:

  1. GitHub Actions builds just enough of the Ethereal Engine monorepo to fetch any installed Ethereal Engine projects.
  2. GitHub Actions pushes this builder Docker image to the repo etherealengine-<release>-builder in ECR
  3. GitHub Actions updates the builder deployment to point to the builder image it just created.
  4. The builder deployment spins up the builder Docker image on its single node
  5. The builder connects to the deployment's database and checks if there is a table user. This is a proxy +for the database being seeded; if it does not exist, it seeds the database with the basic Ethereal Engine schema, +seeds the default project into the database and storage provider, and seeds various types.
  6. The builder downloads any Ethereal Engine projects that the deployment has added.
  7. The builder builds the Docker image for each service concurrently using these projects, building them into the client files as well as copying them so that the api and instanceservers have access to them. +If serving client files from the Storage Provider, the client files will be pushed to S3
  8. The builder pushes these final Docker images to the repos etherealengine-<release>-<service> in ECR (not the client image if serving client files from the Storage Provider)
  9. The builder caches all of the layers of each Docker file in S3 for faster build times on subsequent builds
  10. The builder updates the main deployment to point to the final images it just created.
  11. The main deployment spins up the final Docker images for the api, client (optional), instanceserver and taskserver services.

Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana +Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update config file(values.yml) for Xr env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

Upgrading an existing Helm deployment

One of the features of Helm is being able to easily upgrade deployments with new values. The command to +do this is very similar to the install command:

helm upgrade --reuse-values -f </path/to/*.values.yaml> --set api.image.tag=<latest_github_commit_SHA>,client.image.tag=<latest_github_commit_SHA>,instanceserver.image.tag=<latest_github_commit_SHA> <RELEASE_NAME> etherealengine/etherealengine

--reuse-values says to carry over all configuration values from the previous deployment. This is most important +for tags, since they're usually set inline with the helm install/upgrade command, not a Helm config. +Using -f <config_file> and --set <variables> after it will apply any changes on top of the +carryover values.

If you're not deploying a new build of the codebase, you can skip the entirety of the --set *.image.tag=<SHA>.

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/database_migrations/index.html b/es/docs/host/devops_deployment/database_migrations/index.html new file mode 100644 index 000000000000..4fe95b997ac9 --- /dev/null +++ b/es/docs/host/devops_deployment/database_migrations/index.html @@ -0,0 +1,16 @@ + + + + + +Database Migrations | etherealengine + + + + +
+

Database Migrations

Create Migration File

  1. In your ethereal engine repo run following command
  cd packages/server-core
  1. Afterward run following command to generate migration file: TIMESTAMP_NAME.ts i.e. 20230418102549_eks-column.ts in server-core folder.
  npm run migrate:make -- {NAME}

i.e.

  npm run migrate:make -- eks-column
  1. Move the migration file to your service's migrations folder. i.e. packages/server-core/src/setting/aws-setting/migrations
  2. Update that file with code to match your needs.

OpenAPI

Our server is set up with Swagger documentation to automatically generate from most endpoints. A few custom routes are not documented at this time, but most of the basic stuff is.

You can see the docs for a running Ethereal Engine instance locally at:

https://localhost:3030/openapi

Or on our dev cluster

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/docker_desktop/index.html b/es/docs/host/devops_deployment/docker_desktop/index.html new file mode 100644 index 000000000000..d419d0e286e3 --- /dev/null +++ b/es/docs/host/devops_deployment/docker_desktop/index.html @@ -0,0 +1,49 @@ + + + + + +Ethereal Engine on Docker Desktop | etherealengine + + + + +
+

Ethereal Engine on Docker Desktop

NOTE: UDP networking does not work properly on Docker Desktop as of this writing, as Docker Desktop does not expose the IP addresses/ports of the node publicly, so mediasoup cannot connect over UDP. If you want to test audio/video calling or networked movements, please use minikube.

Install kubectl, Helm, and Docker Desktop

If kubectl, Helm, +and/or Docker Desktop +aren't already installed on your machine, install them. Windows and Mac Docker Desktop installation instructions +can be found here and here.

You may also need to install Docker Compose

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local +services, you'll need to get the Ethereal Engine repo on your machine. This is most easily +done by running git clone https://github.com/etherealengine/etherealengine.git

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_minikube.sh.

Enable Kubernetes in Docker Desktop

Inside Docker Desktop, go to Settings. There should be a section for Kubernetes (as of this writing, located +between Docker Engine and Software updates settings). Click on that, then check the checkbox for Enable Kuberentes, +and then click the button Apply and restart. When Docker Desktop restarts, it should now run a minikube-like Kubernetes +cluster on startup. The Kubernetes context for this should be named docker-desktop.

Edit system hostfile to point EtherealEngine addresses to 127.0.0.1

You'll need to edit your hostfile to point certain domains to 127.0.0.1, which is how Docker Desktop routes traffic +to its Kubernetes cluster. On Linux, this is done by running sudo gedit /etc/hosts.

Add the following line:

127.0.0.1  local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org

You should also see a section that looks like this:

# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

The first line says to point several *-local.etherealengine.org domains internally to the Kubernetes cluster, +where the nginx ingress server will redirect the traffic to the appropriate pod. +The section it automatically added is used for giving Docker containers, including the Kubernetes cluster, +access to the host machine.

Make sure to save this file after you've edited it. On Linux, at least, you need root permissions +to edit it.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at docker-desktop by running kubectl config current-context, +which should say 'docker-desktop'. You can also run kubectl config get-contexts to get all contexts +that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to docker-desktop, from the top of the Ethereal Engine repo, run +helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones +and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in docker-desktop. After a minute or so, +all of these pods should be in the Running state.

Run build_docker_desktop.sh

When docker desktop's Kubernetes cluster is running, run the following command from the root of the Ethereal Engine repo:

./scripts/build_docker_desktop.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

The script builds the full-repo Docker image using several build arguments. Vite, which builds +the client files, uses some information from the MariaDB database created for local K8s deployments +to fill in some variables, and needs database credentials. The script will supply default values +for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, +VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your Docker Desktop K8s deployment +accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different +domain, then you'll have to set those three environment variables to what you want them to be (and also +change the hostfile records you made pointing those subdomains to 127.0.0.1)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for +different services, it will only run the parts needed for that service. This may take up to 15 minutes, +though later builds should take less time as things are cached.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained a couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. It's mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Run the following command: helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine.

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api +servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers +(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run +helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. +The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/index.html b/es/docs/host/devops_deployment/index.html new file mode 100644 index 000000000000..96696416b85e --- /dev/null +++ b/es/docs/host/devops_deployment/index.html @@ -0,0 +1,16 @@ + + + + + +Deployment | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/installing_projects/index.html b/es/docs/host/devops_deployment/installing_projects/index.html new file mode 100644 index 000000000000..980763593eb6 --- /dev/null +++ b/es/docs/host/devops_deployment/installing_projects/index.html @@ -0,0 +1,75 @@ + + + + + +Installing Projects | etherealengine + + + + +
+

Installing Projects

Local Install Flow

To install a project locally, clone the repository you wish to install to the +/packages/projects/projects/ folder. You can do this with the follow commands:

cd packages/projects/projects/
git clone https://github.com/myorg/myrepo
cd myrepo
code .

This will create a folder name myrepo which must contain an xrengine.config.ts +file, and open the project in a new vscode window (such that git commands can be +handled by the new window). All you need to do now to run this project is re-run +the stack (with npm run dev).

Graphical Install Flow

Projects can also be installed and managed from the /admin/projects route. You must be +an admin and must have a linked GitHub account, which can be attained by having your +GitHub account linked to your Ethereal Engine account by signing in via GitHub. +(You do not need to have most recently signed in via GitHub, you just have to have +linked your GH account at some point)

See the section 'How to set up GitHub to install external projects' +for instructions on creating an OAuth app from GitHub, installing it into an Ethereal Engine deployment, +and authorizing it to have access to your GitHub organizations.

Click the 'Add Project' button:

You will see text fields for entering the source and destination repositories. +When you click away from the text fields, the URL will be checked both for the +repository existing, and for whether you have sufficient permission to access +that repository - read permission for the source repo (public repositories are +always available), and write or admin permission for the destination repo. If +you have never logged into GitHub with your current account, you will not be +allowed to add or update projects.

For the source repository, after entering the URL, you will also need to select +a branch to pull from. Your options are either the main branch for that repository, +or a branch that matches the RELEASE_NAME of the deployment, e.g. dev-deployment for +a deployment with the environment variable RELEASE_NAME=dev. If RELEASE_NAME is not defined, then +local is used; this could lead to multiple local installations of the platform conflicting, +but one can set RELEASE_NAME locally to something else in your .env.local file.

After the branch is selected, you also need to select a tagged commit from that branch, +or the most recent commit. As of this writing, you must manually tag project commits yourself, +though tags are copied over from the source repository when installing or updating a project.

The backend checks that the source and destination repos have the same project. +The project name is the name field in the project's package.json file. +If the destination repo's <RELEASE_NAME>-deployment branch is empty or nonexistent, then +any project can be uploaded to it. If the destination deployment branch is not empty, +then it can only be updated with different versions of that project. For example, +if the destination branch has project example1 in it, you will not be allowed to +overwrite it with a project test3, only other projects named example1.

You can only install a project with a given name once, and names are case-insensitive; +example1 is seen as the same name as ExamplE1. You would need to remove an existing project +in order to install a different project that has the same name, or rename one of the projects.

When everything is valid, you will be able to click the Submit button, which will install +the project.

Adding a project through this interface runs git clone in the background, same as above, +but will then upload all of the repository's files to the storage provider. These files will then be +downloaded and installed to the deployment's file system each time the docker builder +pod runs. This allows full version controlled access for local development flow +and version locking for production deployment. The source project code will then be force-pushed +to the branch <RELEASE_NAME>-deployment, so make sure that there is no work in that branch +that might get overwritten, and make a backup in another branch you do want to save it.

The Push to GitHub button will push the current code for that project to the <RELEASE_NAME>-deployment +branch if possible; it will never push to the main branch. If there are merge conflicts, it will instead +make a Pull Request on that branch with the changes; it will NOT force-push anything to this branch, +unlike adding or updating a project.

The Update button opens the same drawer as adding a new project, just with the destination repository locked in. +Assuming everything matches, it will also force-push to the <RELEASE_NAME>-deployment branch in the destination +repository.

The GitHub Repo Link button also opens this drawer, but you can only select the destination repository, not +the source repository, and no code is pushed anywhere.

The remove button will remove the folder containing that project. This will not delete the deployment +branch. WARNING: Any uncommitted & unpushed files will be lost.

Updating the Engine Version and Rebuilding Projects

Making changes to a project is not always reflected immediately in the running code. As of this writing, +project code is built into the client-side and backend files, and changes to project code require that +the codebase be updated. Locally, this just requires you to stop and restart the npm run dev command. +In a production environment, this requires that the builder process be restarted, so that it can +rebuild the client and backend code with the new project code.

Changes to scenes in projects do not require a rebuild - since they are stored external to the codebase +in the storage provider, and are downloaded anew by a client each time the scene is loaded, changes to +scenes will always be immediately available. The act of saving a project will clear any cached version +of the scene's static files, so the client will get the new version.

Additionally, if you want to update the core Ethereal Engine code, you will also need to re-run the builder +process with the new version of the code.

In a production environment, click on the button Update Engine/Rebuild. A drawer will open with +a selector for the engine version you want to update with. This will be an image in the builder's +linked image repository.

After selecting an engine version, if you click Submit now, you will just rebuild with the +newly-selected version of the main codebase, plus whatever versions of your projects are currently +in your linked repositories.

If you click on Update projects, +you can select the source commits for any installed projects that have a destination repo, same as with +the Add/Update project drawer. The projects will be updated before the builder is restarted.

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/managing_remote_kubernetes/index.html b/es/docs/host/devops_deployment/managing_remote_kubernetes/index.html new file mode 100644 index 000000000000..e08f4f062fb4 --- /dev/null +++ b/es/docs/host/devops_deployment/managing_remote_kubernetes/index.html @@ -0,0 +1,18 @@ + + + + + +Cluster Management | etherealengine + + + + +
+
+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/microk8s_linux/index.html b/es/docs/host/devops_deployment/microk8s_linux/index.html new file mode 100644 index 000000000000..8ab647c1d1b2 --- /dev/null +++ b/es/docs/host/devops_deployment/microk8s_linux/index.html @@ -0,0 +1,19 @@ + + + + + +Ethereal Engine on MicroK8s (Linux) | etherealengine + + + + +
+

Ethereal Engine on MicroK8s (Linux)

This guide is intended for local environment and currently tested on Ubuntu.

Install Python 3

In your WSL Ubuntu terminal, if python 3 (pip3 --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y python3-pip

You can verify pip3 by using pip3 --version command.

Install Make

In your WSL Ubuntu terminal, if make (make --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y build-essential

You can verify make by using make --version command.

Install kubectl, Helm and Docker

If kubectl, Helm and Docker aren't already installed on your machine, install them.

You may also need to install Docker Compose

Download and install MicroK8s

Instructions can be found here

sudo snap install microk8s --classic --channel=1.26/stable

Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.

While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it.

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal.

git clone https://github.com/etherealengine/etherealengine.git etherealengine

If .env.local file does not exist in the root of your repo folder then create it by duplicating .env.local.default.

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_microk8s.sh.

Enabling MicroK8s Addons

Execute following command in your terminal to enable MicroK8s addons

sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3

Add MicroK8s to Kubectl

First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run kubectl config get-contexts command in terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:

kubectl config delete-context microk8s
kubectl config delete-cluster microk8s-cluster
kubectl config delete-user microk8s-admin

Now, we will add microk8s configuration to kubectl config. We can do this by using following commands. Reference

kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt
kubectl config set-credentials microk8s-admin --token="$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')"
kubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin

Afterwards you can use this newly create context by executing kubectl config use-context microk8s

Now if you run kubectl config get-contexts command then microk8s should be current context.

(Optional) Add MicroK8s to Lens

If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool Lens. Else you can print the configuration using following command:

microk8s config

Option 1: If you have kubectl already installed, use sudo gedit ~/.kube/config as add the above output in it.
+Option 2: In Lens, goto File > Add Cluster and paste the output of above command to add cluster.

Enable MicroK8s access for local docker

For MicroK8s we will be using MicroK8s local registry

Add the following lines to /etc/docker/daemon.json. On Linux, this is done by running sudo gedit /etc/docker/daemon.json.

{ 
"insecure-registries" : ["localhost:32000"]
}

Afterwards, restart docker with: sudo systemctl restart docker

Verify and troubleshoot MicroK8s

Run sudo microk8s inspect and check if there is any warning. Its recommended to fixed the warning for MicroK8s to work properly. Following are some of the warnings and their possible fixes:

  1. WARNING: This machine's hostname contains capital letters and/or underscores. This is not a valid name for a Kubernetes node, causing node registration to fail. Please change the machine's hostname or refer to the documentation for more details.

    Possible Fix: https://askubuntu.com/a/87687/1558816

  2. WARNING: The memory cgroup is not enabled. The cluster may not be functioning properly. Please ensure cgroups are enabled

    Possible Fix: https://github.com/canonical/microk8s/issues/1691#issuecomment-1265788228

  3. WARNING: IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: sudo iptables -P FORWARD ACCEPT

    The change can be made persistent with: sudo apt-get install iptables-persistent

  4. MicroK8s is not running. Use microk8s inspect for a deeper inspection.

    Possible Fix: https://lightrun.com/answers/canonical-microk8s-microk8s-is-not-running-microk8sinspect-showing-no-error

    Here this error cloud be due to conflicting kubectl being installed. Use this command to remove kubectl sudo rm -rf /usr/local/bin/kubectl

Update system hostfile to point to MicroK8s

You'll need to edit your hostfile to point certain domains to host machine IP address. On Linux, this is done by running sudo gedit /etc/hosts.

Add/Update the following lines:

127.0.0.1 local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org

The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod.

Make sure to save this file after you've edited it. On Linux, at least, you need root permissions to edit it.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at MicroK8s by running kubectl config current-context, which should say 'microk8s'. You can also run kubectl config get-contexts to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state.

(Optional) Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana

Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update local.microk8s.template.values.yaml env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

local.microk8s.template.values.yaml can be found in ethereal-engine-ops repo.

Run build_microk8s.sh

When microk8s is running, run the following command from the root of the Ethereal Engine repo:

./scripts/build_microk8s.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached.

Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting http://localhost:32000/v2/_catalog.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Run the following command: helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine.

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/microk8s_windows/index.html b/es/docs/host/devops_deployment/microk8s_windows/index.html new file mode 100644 index 000000000000..e1125424c266 --- /dev/null +++ b/es/docs/host/devops_deployment/microk8s_windows/index.html @@ -0,0 +1,18 @@ + + + + + +Ethereal Engine on MicroK8s (Windows) | etherealengine + + + + +
+

Ethereal Engine on MicroK8s (Windows)

This guide is intended for local environment and currently tested on Windows 11.

Install Windows Subsystem for Linux (WSL)

Install Ubuntu distribution of Linux from Microsoft Store by using guide here.

Alternatively, you can follow these instructions as well:

Once WSL is installed, make sure to:

Set Ubuntu as default WSL distribution

In powershell/cmd run following command to see the list of distributions:

wsl -l

In the list you should be able to see Ubuntu listed. Afterwards, run following command to set Ubuntu as default distribution:

wsl -s Ubuntu

WSL Ubuntu Default Distribution

Install Docker Desktop

Install docker desktop with WSL 2 backend. You can find the instructions here.

Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting Settings > Resources > WSL Integration. Make sure to hit 'Apply & Restart'.

Docker Desktop WSL Distro

Enable systemd in WSL

Inside your Ubuntu instance, add the following modification to /etc/wsl.conf.

[boot]
systemd=true

Then restart your instance by running wsl --shutdown in PowerShell and relaunching Ubuntu. Upon launch you should have systemd running. You can check this with the command systemctl list-unit-files --type=service which should show your services status.

You can read more about this on Ubuntu blog & Microsoft blog.

Enable localhostForwarding in WSL

Create or update .wslconfig file located at C:\Users\{USER_NAME}\.wslconfig (Or %UserProfile%\.wslconfig) with following content:

[wsl2]
localhostForwarding=true

This requires WSL shutdown and reboot. Shutting down your terminal is insufficient. Also machine boot is not required. Simply run:

wsl --shutdown (in Powershell) or 
wsl.exe --shutdown (within Ubuntu)

Reference: Custom hostname for servers running in WSL 2

Install Node

In your WSL Ubuntu terminal, if node (node --version) isn't already installed on your machine. You can do so by first installing nvm by running following commands:

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source ~/.profile

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

You can verify nvm by using nvm --version command. Afterwards, install node by using:

nvm install --lts

You can verify nvm by using node --version command.

Install Python 3

In your WSL Ubuntu terminal, if python 3 (pip3 --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y python3-pip

You can verify python3 by using python3 --version command.

Install Make

In your WSL Ubuntu terminal, if make (make --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y build-essential

You can verify make by using make --version command.

Install kubectl and Helm

In your WSL Ubuntu terminal, if kubectl & Helm aren't already installed on your machine, install them.

Docker & Docker Compose should be installed if you successfully completed "Install Docker Desktop" step. You can verify by running docker --version & docker-compose --version commands in WSL Ubuntu terminal.

Download and install MicroK8s

Make sure to install MicroK8s in your WSL Ubuntu terminal. Instructions can be found here

sudo snap install microk8s --classic --channel=1.26/stable

Due to some ongoing issue with host storage access in microk8s 1.25 version, it is recommended to use version 1.26.

While you can follow the demo instructions there about starting MicroK8s, deploying some demo deployments, etc. to get a feel for it.

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local services, you'll need to get the Ethereal Engine repo on your machine. This is most easily done by running following command in WSL Ubuntu terminal.

git clone https://github.com/etherealengine/etherealengine.git etherealengine

If .env.local file does not exist in the root of your repo folder then create it by duplicating .env.local.default.

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_microk8s.sh.

Enabling MicroK8s Addons

Execute following command in your WSL Ubuntu terminal to enable MicroK8s addons

sudo microk8s enable dashboard dns registry host-access ingress rbac hostpath-storage helm3

Add MicroK8s to Kubectl

First make sure there is no existing configuration for microk8s in your kubectl config. To do so you run kubectl config get-contexts command in WSL Ubuntu terminal and see if the output contains microk8s. You can remove the existing configurations using following commands:

kubectl config delete-context microk8s
kubectl config delete-cluster microk8s-cluster
kubectl config delete-user microk8s-admin

Now, we will add microk8s configuration to kubectl config. We can do this by using following commands in WSL Ubuntu terminal. Reference

kubectl config set-cluster microk8s --server=https://127.0.0.1:16443/ --certificate-authority=/var/snap/microk8s/current/certs/ca.crt
kubectl config set-credentials microk8s-admin --token="$(sudo microk8s kubectl config view --raw -o 'jsonpath={.users[0].user.token}')"
kubectl config set-context microk8s --cluster=microk8s --namespace=default --user=microk8s-admin

Afterwards you can use this newly create context by executing:

kubectl config use-context microk8s

Now if you run kubectl config get-contexts command then microk8s should be current context.

(Optional) Add MicroK8s to Lens

If the previous step was performed successfully then you should be able to see MicroK8s cluster in GUI tool Lens. Else you can print the configuration using following command:

microk8s config

In Lens, goto File > Add Cluster and paste the output of above command to add cluster.

Enable MicroK8s access for local docker

For MicroK8s we will be using MicroK8s local registry

Option 1: In Windows, add the following lines to %userprofile%\.docker\daemon.json. Create this file if it does not already exists.

{ 
"insecure-registries" : ["http://microk8s.registry:32000", "microk8s.registry:32000"]
}

Afterwards, restart docker from Powershell: restart-service *docker*

Option 2: Edit configuration as shown in below image. Make sure to hit 'Apply & Restart' after making changes.

Docker Desktop Configuration

Reference:

Verify and troubleshoot MicroK8s

Run following command and check if there is any warning. Its recommended to fix the warnings for MicroK8s to work properly.

sudo microk8s inspect

Update system hostfile to point to MicroK8s

You'll need to edit your hostfile to point certain domains to host machine IP address. First you need to find the IP address of your WSL. Run wsl hostname -I in powershell/cmd. For example:

C:\Users\hanzl>wsl hostname -I
172.31.89.133 10.1.215.0

Note: If you face issue while running above command, make sure that 'Ubuntu' distribution is selected as default. You can do so by running wsl /l to view distributions and then run wslconfig /s Ubuntu to select distribution.

From the above output, use 172.31.89.133 as {WSL_IP}.

Note: Your ip would be different, this is just for example.

Next, edit your Windows hostfile, this is done by editing C:\Windows\System32\drivers\etc\hosts. Add/Update the following lines:

{WSL_IP} local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org

{WSL_IP} microk8s.registry

Make sure to replace {WSL_IP} with ip address from wsl hostname -I command.

The first line says to point several *-local.etherealengine.org domains internally to the host machine, where the nginx ingress server will redirect the traffic to the appropriate pod.

Make sure to save this file after you've edited it. Also, you will need to update hostfile with updated ip address after every Windows/WSL reboot.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at MicroK8s by running kubectl config current-context, which should say 'microk8s'. You can also run kubectl config get-contexts to get all contexts that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to microk8s, from the top of the Ethereal Engine repo, run helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in microk8s. After a minute or so, all of these pods should be in the Running state.

(Optional) Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana

Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update local.microk8s.template.values.yaml env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

local.microk8s.template.values.yaml can be found in ethereal-engine-ops repo.

Run build_microk8s.sh

When microk8s is running, run the following command from the root of the Ethereal Engine repo in WSL Ubuntu terminal:

export REGISTRY_HOST=microk8s.registry; export MYSQL_HOST=kubernetes.docker.internal;bash ./scripts/build_microk8s.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your WSL terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

The script builds the full-repo Docker image using several build arguments. Vite, which builds he client files, uses some information from the MariaDB database created for microk8s deployments to fill in some variables, and needs database credentials. The script will supply default values for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your microk8s deployment accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different domain, then you'll have to set those three environment variables to what you want them to be (and also change the hostfile records you made pointing those subdomains)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for different services, it will only run the parts needed for that service. This may take up to 15 minutes, though later builds should take less time as things are cached.

Once the images are build. It will push it to MicroK8s local registry. You can verify that images are pushed to registry by visiting http://microk8s.registry:32000/v2/_catalog.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value similar to '<ENGINE_FULL_PATH>/packages/server/upload' e.g. '/home/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. Its mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Before this step, ensure that all the agones and redis pods are in "Running" state. You can check pods status using the below command.

kubectl get pods

Run the following command:

helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers (re)initialize the database. Since you don't want that to happen every time a new api pod starts, run helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/minikube/index.html b/es/docs/host/devops_deployment/minikube/index.html new file mode 100644 index 000000000000..447d8334fc87 --- /dev/null +++ b/es/docs/host/devops_deployment/minikube/index.html @@ -0,0 +1,59 @@ + + + + + +Ethereal Engine on Minikube | etherealengine + + + + +
+

Ethereal Engine on Minikube

Install kubectl, Helm, Docker, and VirtualBox

If kubectl, Helm, +Docker and/or VirtualBox +aren't already installed on your machine, install them.

You may also need to install Docker Compose

Download and install minikube

Instructions can be found here

While you can follow the demo instructions there about starting minikube, deploying +some demo deployments, etc. to get a feel for it, before deploying Ethereal Engine you should delete +your minikube cluster, since we have some specific starting requirements.

Clone Ethereal Engine repo to your local machine

To build the Ethereal Engine Docker image locally, and to have a pre-tested way to run various local +services, you'll need to get the Ethereal Engine repo on your machine. This is most easily +done by running git clone https://github.com/etherealengine/etherealengine.git

Start MinIO & MariaDB server locally via Docker

For simplicity, we recommend running MinIO & MariaDB server on your local machine outside of MicroK8s.

If you run docker-compose up from the top-level /scripts directory in the Ethereal Engine repo, it will start up MinIO & multiple MariaDB docker containers (as well as a redis server, which is not needed). For mariadb containers, one is intended for local development, runs on port 3306; another, intended for automated testing purposes, runs on port 3305; and the last one, intended for minikube/microk8s testing, runs on port 3304. Once the docker container is stopped, you can start it again by running npm run dev-docker.

Alternatively, if you want to just run MinIO & MariaDB on its own without Docker, that's fine too. You'll just have to configure the Helm config file to have the appropriate S3 & SQL server configuration, and possibly change the script ./scripts/build_minikube.sh.

Create minikube cluster

Run the following command: +minikube start --disk-size 40000m --cpus 4 --memory 10124m --addons ingress --driver virtualbox

This says to start minikube with 40GB of disk space, 4 CPUs, 10GB of memory, using VirtualBox as its +driver, and starting up an nginx ingress service.

The disk space, CPUs, and memory allocation are configurable. These are what we recommend for optimal +running (though the disk space might be a bit more than necessary). When minikube is running, +it will reserve those resources for itself regardless of whether the services in minikube are using +that much.

The 10GB of memory might be the spec with the least wiggle room. Later instructions on building +the Docker image will have it be built in the minikube context. This uses the RAM reserved for minikube, +and the client build process normally uses about 8GB of RAM at its peak. minikube may freeze if +it gets maxed out on RAM, and the Docker build process might freeze indefinitely.

Starting ingress after minikube has started

If you forget to use --addons ingress when starting minikube, you can start nginx later by +running minikube addons enable ingress

Get minikube IP address and edit system hostfile to point to

Run this command after minikube has started: minikube ip +This will get you the address that minikube is running on.

You'll need to edit your hostfile to point certain domains to minikube IP addresses. On Linux, +this is done by running sudo gedit /etc/hosts.

Add the following lines:

<Output of 'minikube ip'>  local.etherealengine.org api-local.etherealengine.org instanceserver-local.etherealengine.org 00000.instanceserver-local.etherealengine.org 00001.instanceserver-local.etherealengine.org 00002.instanceserver-local.etherealengine.org 00003.instanceserver-local.etherealengine.org
10.0.2.2 host.minikube.internal

The first line says to point several *-local.etherealengine.org domains internally to the minikube cluster, +where the nginx ingress server will redirect the traffic to the appropriate pod. +The second line is used to give minikube access to your local environment, particularly so that it +can access the MariaDB server.

Make sure to save this file after you've edited it. On Linux, at least, you need root permissions +to edit it.

Add Helm repos

You'll need to add a few Helm repos. Run the following:

helm repo add agones https://agones.dev/chart/stable
helm repo add redis https://charts.bitnami.com/bitnami
helm repo add etherealengine https://helm.etherealengine.org

This will add the Helm charts for Agones, Redis, and Ethereal Engine, respectively.

Install Agones and Redis deployments

After adding those Helm repos, you'll start installing deployments using Helm repos.

Make sure that kubectl is pointed at minikube by running kubectl config current-context, +which should say 'minikube'. You can also run kubectl config get-contexts to get all contexts +that kubectl has been configured to run; the current one will have a '*' under the left-most +'current' column.

Once kubectl is pointed to minikube, from the top of the Ethereal Engine repo, run +helm install -f </path/to/agones-default-values.yaml> agones agones/agones to install Agones +and helm install local-redis redis/redis to install redis.

agones-default-values.yaml can be found in ethereal-engine-ops repo.

You can run kubectl get pods -A to list all of the pods running in minikube. After a minute or so, +all of these pods should be in the Running state.

Install Elastic Search and Kibana using Helm for Server Logs

To install Elasticsearch, add the elastic repository in Helm: helm repo add elastic https://helm.elastic.co

Now, use the curl command to download the values.yaml file containing configuration information:

curl -O https://raw.githubusercontent.com/elastic/helm-charts/master/elasticsearch/examples/minikube/values.yaml

Use the helm install command and the values.yaml file to install the Elasticsearch helm chart:

helm install elasticsearch elastic/elasticsearch -f ./values.yaml

The -f option allows specifying the yaml file with the template. If you wish to install Elasticsearch in a specific namespace, add the -n option followed by the name of the namespace: helm install elasticsearch elastic/elasticsearch -n [namespace] -f ./values.yaml

Now check if the cluster members are up: kubectl get pods --namespace=default -l app=elasticsearch-master -w

The other option is to use the helm test command to examine the cluster’s health: helm test elasticsearch

To install Kibana on top of Elasticsearch : helm install kibana elastic/kibana

Check if all the pods are ready: kubectl get pods

After you set up port-forwarding, access Elasticsearch, and the Kibana GUI by typing http://localhost:5601 in your browser

In order to connect logger with elasticsearch, update local.minikube.template.values.yaml env api.extraEnv.ELASTIC_HOST for e.g. http://<username>:<password>@<host>:<port>

local.minikube.template.values.yaml can be found in ethereal-engine-ops repo.

Run build_minikube.sh

When minikube is running, run the following command from the root of the Ethereal Engine repo:

./scripts/build_minikube.sh

If you face issue related to "packages/projects/projects/" does not exist then run following commands in your terminal:

export MYSQL_HOST=localhost
npm run dev-docker
npm run dev-reinit
npm run install-projects

This points Docker in the current terminal to minikube's Docker environment. Anything that Docker builds +will be locally accessible to minikube; if the first main command in the script were not run, Docker would build to your +machine's Docker environment, and minikube would not have access to it.

The script also builds the full-repo Docker image using several build arguments. Vite, which builds +the client files, uses some information from the MariaDB database created for minikube deployments +to fill in some variables, and needs database credentials. The script will supply default values +for all of the MYSQL_* variables if they are not provided to the script, as well as VITE_CLIENT_HOST, +VITE_SERVER_HOST, and VITE_INSTANCESERVER_HOST. The latter three will make your minikube deployment +accessible on (local/api-local/instanceserver-local).etherealengine.org; if you want to run it on a different +domain, then you'll have to set those three environment variables to what you want them to be (and also +change the hostfile records you made pointing those subdomains to minikube's IP)

This will build an image of the entire Ethereal Engine repo into a single Docker file. When deployed for +different services, it will only run the parts needed for that service. This may take up to 15 minutes, +though later builds should take less time as things are cached.

Update Helm Values File

This will use a Helm config file titled 'local.values.yaml' to configure the deployment. There is +a template for this file in ethereal-engine-ops repo.

If you are using local file server as explained couple of steps earlier then, update 'local.values.yaml' variable api.fileServer.hostUploadFolder with value e.g. '/hosthome/<OS_USER_NAME>/<ENGINE_FOLDER>/packages/server/upload'. The folder must be in home folder and make sure to use /hosthome/ instead of home in path. Its mandatory to point to /packages/server/upload folder of your engine folder.

Deploy Ethereal Engine Helm chart

Run the following command: helm install -f </path/to/local.values.yaml> -f </path/to/db-refresh-true.values.yaml> local etherealengine/etherealengine.

db-refresh-true.values.yaml can be found in ethereal-engine-ops repo.

After a minute or so, running kubectl get pods should show one or more instanceservers, one or more api +servers, and one client server in the Running state. Setting FORCE_DB_REFRESH=true made the api servers +(re)initialize the database. Since you don't want that to happen every time a new api pod starts, run +helm upgrade --reuse-values -f </path/to/db-refresh-false.values.yaml> local etherealengine/etherealengine. +The API pods will restart and will now not attempt to reinit the database on boot.

db-refresh-false.values.yaml can be found in ethereal-engine-ops repo.

Accept invalid certs

Since there are no valid certificates for this domain, you'll have to tell your browser to ignore the insecure connections when you try to load the application.

Go to https://local.etherealengine.org/, you should see a warning about an invalid certificate; accept this invalid cert to get to the home page. Next if it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates. You'll have to open the dev tools for your browser and go to the 'Console' tab. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab. You need to do this for following domains:

You can open Developer tools in Chrome by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I)

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/release_helm_chart/index.html b/es/docs/host/devops_deployment/release_helm_chart/index.html new file mode 100644 index 000000000000..0e92728d9c47 --- /dev/null +++ b/es/docs/host/devops_deployment/release_helm_chart/index.html @@ -0,0 +1,16 @@ + + + + + +Release Helm Chart | etherealengine + + + + +
+

Release Helm Chart

Following are the steps that needs to be taken in order to update etherealengine helm charts repo:

  • Have a checked-out copy of https://github.com/EtherealEngine/ethereal-engine-helm, set to the gh-pages branch
  • Have a checked-out copy of https://github.com/EtherealEngine/ethereal-engine-ops, set to the master branch
  • Set working directory to local ethereal-engine-ops folder
  • Increase the version number in etherealengine/Chart.yaml
  • Run helm package etherealengine
  • Run helm repo index --url https://helm.etherealengine.org .
  • Copy etherealengine-X.Y.Z.tgz that's generated to the root of the ethereal-engine-helm repo, and make sure to git add it.
  • Open index.yaml. Under entries.xrengine, there should be an entry for the new version.
  • Copy that entry to ethereal-engine-helm's index.yaml, making sure to put it under the right entries section; we've got etherealengine-builder and etherealengine in the same file, so pay attention to which one you're putting it in. Also make sure that the spacing/indentation matches the other entries.
  • Copy the generated line from index.yaml to ethereal-engine-helm/index.yaml, overwriting the generated line that's there.
  • Commit this, and push it to the gh-pages branch of ethereal-engine-helm. Within a couple of minutes, you should see the new version appear at https://helm.etherealengine.org/
+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/setup_github_oauth_for_projects/index.html b/es/docs/host/devops_deployment/setup_github_oauth_for_projects/index.html new file mode 100644 index 000000000000..1d49ebb12558 --- /dev/null +++ b/es/docs/host/devops_deployment/setup_github_oauth_for_projects/index.html @@ -0,0 +1,85 @@ + + + + + +How to set up GitHub to install external projects | etherealengine + + + + +
+

How to set up GitHub to install external projects

Ethereal Engine is extensible via Projects, which can contain +new scenes, new avatars, new static resources, additional code, and more. Ethereal Engine integrates +with GitHub to push and pull projects for backup and restoration, and one can also install existing +projects from GitHub. In order to install projects from private repositories, or to push local project +changes to a GitHub repo, an OAuth app from GitHub (not a GitHub app, that is something different) needs to be +created, and the logged-in user must be connected in Ethereal Engine to GitHub (i.e. must have logged in via +GitHub at some point) and have permission to access the source and destination repositories.

Note that it is recommended that you complete most of this before the initial installation of +your deployment, so that you can log in via GitHub and be granted admin status as the first +logged-in user. If you do not, then you will either need to manually insert some of these values +into the database so that you can log yourself in; have another log method configured already +and use that logged-in admin user; or reset the database with these values configured in the +updated Helm configuration that is used for the reset.

Create a GitHub OAuth App in an organization, or your user

You can either create an OAuth App for your personal GitHub account or for an organization that +you have sufficient permissions on. Either will work for this setup.

The general instructions for doing this can be found here. +The specifics you'll need to enter are as follows:

  • Application name: Anything you want
  • Homepage URL: Whatever you want, this is just what is linked to from the OAuth authorization page
  • Authorization callback URL: enter https://api.<domain>/oauth/github/callback, e.g. https://api.example.com/oauth/github/callback. ^
  • Enable Device Flow: Leave unchecked

^If you are running this locally off of localhost, this should be https://localhost:3030/oauth/github/callback. +If you are using an explicit IP address instead of localhost, then use that IP address here, but keep the :3030, +as that is the port that the API server runs on, and GitHub needs to call back to the API server.

Create client secret, note Client ID

Once the app has been created, you will be redirected to the General settings for it. +Here, you will generate one credential for the app, so that your deployment can be authenticated.

Make note of Client ID

Near the top of this page is the Client ID for the app. This is a public ID for the app. +It will be used when configuring Ethereal Engine.

Generate client secret

Below Client ID is a section Client secrets. None are created by default, so click the +button Generate a new client secret. As the notifications that appear say, you will only see the +full secret right now, so copy it somewhere retrievable (but not anywhere publicly accessible). If +you ever lose the secret, you can always generate a new one.

Configure Ethereal Engine deployment with IDs/keys

Pre-initial installation

If you have not done the initial installation/deployment yet, then you can add most of the values +above to the Helm configuration, and they will be inserted into the database so that GitHub login +is enabled from the start, and you can then log in via GitHub and be granted admin status.

Enter the Client ID for GITHUB_CLIENT_ID, and the Client secret for +GITHUB_CLIENT SECRET in the section api.extraEnv. It is advised that you enclose all of these in +double quotes in the .yaml file, so that they are interpreted as strings even if they start with a +number, e.g. GITHUB_CLIENT_ID: "17592577832789234" If you see GITHUB_APP_ID, it is not used; +it is left over from a prior implementation of GitHub Apps, which no longer works.

Continue with the setup instructions. When you run helm install with your configuration file, the +GitHub credentials will be included.

Post-installation, if you have another authentication method configured

If you have already installed the platform but configured it with another login method, such as +email or another OAuth provider, then log in as an admin user. If you haven't logged in with anything +yet, then the first user that logs in will be made an admin.

Go to /admin/settings. Click on the Authentication selector. A page should open with a +section OAuth that takes up the bottom two-thirds. Under GitHub, enter +the Client ID under Key and the Client Secret under Secret. Click the Save button at the bottom.

Post-installation, if you do not have any authentication method configured

If you have already set up the platform but did not configure any authentication method, +then you are in a bit of a bind where you can't log in to get admin privileges, but need admin +privileges to configure an authentication method. The way around this is to reset the database +and provide the GitHub credentials as part of this process - this is similar to what would happen +on initial installation. Note that this will erase anything you've done so far, but without any +admins, the most you'd have been likely to do is change some guest users' avatars.

Open your Helm configuration. Enter the Client ID for GITHUB_CLIENT_ID and the Client secret for +GITHUB_CLIENT SECRET in the section api.extraEnv. It is advised that you enclose all of these in +double quotes in the .yaml file, so that they are interpreted as strings even if they start with a +number, e.g. GITHUB_CLIENT_ID: "17592577832789234"

Next, run helm upgrade --reuse-values -f <path/to/configuration.yaml> --set-string api.extraEnv.FORCE_DB_REFRESH=true <stage_name> etherealengine/etherealengine. +This tells Helm to restart the API servers, and for them to wipe the database and reseed it with the values +in the configuration file. It should only take a minute or two, and you should then run +helm upgrade --reuse-values --set-string api.extraEnv.FORCE_DB_REFRESH=false <stage_name> etherealengine/etherealengine to unset +the flag telling it to reset the database.

Once this is done, you should be able to log in with GitHub and be granted admin status.

Logging in with GitHub and Granting Access to Other Organizations

When you log in with GitHub, you will be asked to grant access to your user information as well as the repositories +that the OAuth app has authorized for. Ethereal Engine will have access to your personal repositories and, +if the OAuth app was created in a GitHub organization, all repositories in that organization. It will not +have inherent push access to other organizations' repositories or pull access to their private repositories.

There are two ways to grant access to other repositories. When you are first signing in via GitHub and are +presented with the screen to authorize the OAuth app's permissions, you should see a section near the bottom +that shows all of the organizations you are in. If you have admin rights to that organization, you can Grant +access. If you do not have admin rights, then you can Request access, and someone who does have admin rights +will have to approve it.

If you have already gone through the OAuth approval page, it will not be shown again - all subsequent logins +will bypass this page1. In order to grant the OAuth app access to other organizations, follow +these steps

In short form:

  1. Go to (https://github.com/settings/applications)
  2. Click on the name of the OAuth app installed in Ethereal Engine
  3. Under Organization access, click on Grant/Request for the organizations you want Ethereal Engine to +have access to

Installing Ethereal Engine projects from GitHub

See the section 'Graphical Install Flow for more information on how to install +projects from GitHub.

User Repo Access to GitHub (with optional webhooks)

Users can push projects to GitHub if they have write/maintain/admin access to the associated GitHub repository. +Since fetching this access from the GitHub API every time a user fetches their projects can take a noticeable +amount of time, Ethereal Engine stores users' GitHub repo access in its database. This is much faster to access.

There are multiple actions that will make the engine re-fetch and update users' repo access:

  • When a user logs in via GitHub
  • When a user clicks on the button "Refresh GitHub Repo Access" on /admin/projects or /studio (must be logged +in as a user that is associated with a GitHub account)
  • Via a GitHub webhook - must manually configure this

Setting up GitHub webhook

Ethereal Engine currently only supports webhook notifications for Collaborators being added/edited/removed. +Changes in Teams are not handled by Ethereal Engine due to the opacity of team members. (Team change webhooks do not +include team members, and the engine does not track who is in a team)

An admin needs to go to /admin/settings, click on 'Server', then enter a secret key in the field +"GitHub Webhook Secret", then click the Save button. The secret can be any string you make up. +Randomly generated strings are encouraged.

Next, go to GitGub. In the Repository or Organization that you want to send updates for, go to +Settings -> Code(, planning,) and automation -> Webhooks, then click "Add webhook".

For Payload URL, enter <your_api_subdomain>/github-repo-access-webhook, e.g. https://api.example.com/github-repo-access-webhook +Set Content Type to application/json. For Secret, enter the secret from the earlier step. For +"Which events would you like to trigger this webhook?", select "Let me select individual events." +In the list of events that appears, uncheck "Pushes", anf check "Collaborator add, remove, or changed". +At the very bottom of the page, click the green button "Add webhook".

After the webhook is created, the webhook will send a ping request to the API endpoint you provided. If the URL +was entered correctly, and the secret was entered correctly in both ends, the ping should get a 200 response. +You can check the status under the "Recent Deliveries" tab of that webhook on GitHub.

When this is working, whenever a user is added, removed, or has their access modified, the engine +will re-fetch the user's full set of GitHub repo accesses and update the database's records.

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started/index.html b/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started/index.html new file mode 100644 index 000000000000..fae44d609279 --- /dev/null +++ b/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_started/index.html @@ -0,0 +1,17 @@ + + + + + +Getting Started | etherealengine + + + + +
+

Getting Started

The Ethereal Engine Control Center is a self-contained Metaverse world in a box. Take what you need or launch the full stack. Ethereal Engine Control Center is a desktop app to manage an Ethereal Engine cluster.

We know it's been complicated to build with Ethereal Engine and we've made this tool to give the community easy access to the engine. We would love to see your creations and invite you all to come build with us.

App Overview

The Ethereal Engine Control Center app provides access to various functionalities which includes:

  • Configure your Ethereal Engine in a cluster in just a few clicks.
  • View status of Ethereal Engine dependencies on your local system.
  • Manage an Ethereal Engine deployment through admin panel.
  • Manage kubernetes cluster through its dashboard.
  • Manage IPFS node running in the cluster.
  • Execute commands against rippled server.
  • See realtime logs of different actions being performed.

1. Downloading Control Center App

In order to download Ethereal Engine Control Center App, navigate to releases page and download the latest version of the App. On Windows (and for WSL), you will need to download .exe while for linux download AppImage.

On Windows, you will need to allow permission for executing ps1 scripts. You can do so by running following command in Powershell with admin privileges (reference).

Set-ExecutionPolicy -ExecutionPolicy Unrestricted

On Linux, once downloaded, right click and go to Properties of AppImage. In Permissions tab check 'Allow executing file as program'. Afterwards, double click on AppImage to launch the app.

On Ubuntu 22.04 or later, if you are unable to launch AppImage then you might have to install Fuse using following command in terminal (reference).

sudo apt-get install fuse libfuse2

2. Launch & Create Cluster

When you launch the app for the first time, you will see below screen:

Home Screen

Here you need to create a cluster. You can do so by clicking on Create button in the center or anytime using round plus button on left bottom corner (in hotbar) of the screen. Following are the different sections of create cluster dialog:

2.1. Cluster Information

Create Cluster - Cluster Information

In this step, you will need to provide following information:

  • Cluster Name: This can be any name you want to give your cluster. i.e. Local, my-metaverse, etc.

  • Cluster Type: This will be the kubernetes distribution you want to use. Currently there are 2 local distributions, MicroK8s(recommended) & Minikube. There is also a Custom type which allows you to connect to an existing Ethereal Engine cluster.

    Currently, MicroK8s is supported on Windows & Linux while Minikube is supported on Linux only.

  • Prerequisites: These are the set of items that should be manually configured by the user. If an item is correctly setup then its status will be green tick, else it will have a red cross with details and link to docs for the corrective measures.

    Currently, there are prerequisites for MicroK8s in Windows only.

2.2. Cluster Type: MicroK8s or Minikube

If you selected cluster type as MicroK8s or Minikube, then you will see below options.

2.2.1. Authentication

Create Cluster - Authentication

In this step, you need to provide sudo password for linux terminal. This is because Control Center App will perform various actions on your system with admin privileges.

On Windows, this is the password of your WSL Ubuntu distribution's sudo user.

2.2.2. Configurations

Create Cluster - Configurations

In this step, you will need to provide following information:

  • Engine Path: This is the location of ethereal engine source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Ops Path: This is the location of ethereal engine ops source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Enable Ripple Stack: By default you should keep this option as off unless you want to have IPFS & rippled server running in your local K8s deployment.

  • Force DB Refresh: This will truncate database tables & repopulate them with seed data.

    If the database is empty, then Control Center App will itself force populate it.

2.2.3. Variables

Create Cluster - Variables

In this step for most of the users, go with the default variable values and leave the text fields as it is.

For advanced setup, if you want to configure oAuth, S3 file storage, email, SMS support then you can provide variable values.

2.2.4. Summary

Create Cluster - Summary

This step will show a summary of all the previous steps. User can review them before proceeding ahead.

Please make sure to read Note on this screen.

Afterwards, there are following option(s):

  • Create: By default you should go with this option as it will create the cluster entry and show the cluster screen of this cluster.

  • Create & Configure: This will create the cluster entry and show the current status of things. And afterwards it will automatically start the configuration script to ensure things are setup.

If you use 'Create' option, then you can still run the Configure script as discussed later in this guide.

2.3. Cluster Type: Custom

If you selected Custom cluster type, then you will see below options. Custom cluster allows to connect to an existing kubernetes cluster.

2.3.1. Kubeconfig

Create Cluster - Kubeconfig

In this step, you will need to provide following information regarding desired cluster's kubeconfig:

  • Config Type - Default: This will load the default kubeconfig file of your system.

  • Config Type - File: This will allow to load kubeconfig from a file of your system.

  • Config Type - Text: This will allow to load kubeconfig from a text.

  • Context: This is the selected kube context of cluster in which your ethereal engine deployment exists. The dropdown will show all contexts that exist in selected config type.

2.3.2. Deployment

Create Cluster - Deployment

In this step, you will need to provide following deployment information:

  • Release Name: This is the name of your release in selected kubernetes deployment. It can be 'dev', 'prod', 'local', etc.

    Release name is used to prefix the workloads in your cluster like: +{RELEASE_NAME}-etherealengine-client. i.e. prod-etherealengine-client

2.3.3. Summary

Create Cluster - Summary

This step will show a summary of all the previous steps. User can review them before proceeding ahead.

Please make sure to read Note on this screen.

Afterwards, there are following option(s):

  • Create: This option will create the cluster entry and show the workloads screen of this cluster.

3. Cluster Screen

Cluster Screen

Once you have created a cluster you will be navigated to its screen also know as config page. Lets explain various sections of this screen:

3.1. Hotbar

Hotbar

It will show you a list of all clusters you have created. You can click on each of them to view the cluster screen of them.

Add Cluster Icon The plus icon at the bottom of this bar is used to create a new cluster.

3.2. Navbar

Navbar

This section allows navigation and various utility options. Following are the various options in it:

  • App Icon: App Icon Logo of this application.

  • Home Icon: Home Icon Navigate to home.

  • Config: Navigates to cluster screen of selected cluster.

  • Workloads: Navigates to workloads screen of selected cluster.

  • Admin: Navigates to ethereal engine admin panel of selected cluster.

  • K8 Dashboard: Navigates to kubernetes web dashboard of selected kubernetes distribution.

  • IPFS: Navigates to IPFS web UI of selected cluster. This option is visible only if ripple stack is enabled.

  • Rippled CLI: Navigates to rippled server cli of selected cluster. This option is visible only if ripple stack is enabled.

  • Change Theme Icon: Change Theme Icon Allows to toggle between vaporware, light & dark themes. The color scheme of these themes are similar to ethereal engine.

  • Support Icon: Support Icon Opens a dropdown menu to allow reaching out to support via Discord or Github.

  • User Icon: User Icon The functionality for this button is coming soon.

3.3. Options Panel

Options Panel

This section shows various actions against currently selected cluster. Following are the options in it:

  • Cluster Icon: Cluster Icon Logo of the selected cluster type. It can be MicroK8s or Minikube logo.

  • Cluster Name: This is the cluster name that you entered in create cluster dialog. i.e. Local.

  • Engine Git Status: Cluster Icon This is used to view current status of local ethereal engine github repo. You can view & change current branch, view & pull incoming changes, view & push outgoing changes.

  • Ops Git Status: Cluster Icon This is used to view current status of local ethereal engine ops github repo. You can perform all actions as explained for engine git status.

  • Refresh Icon: Refresh Icon This will recheck the status of prerequisites, system, apps & engine. It also, recheck the status of engine and ops git repos. If a refresh is already in process then it will be disabled until its finished.

  • Delete Icon: Delete Icon This will delete a clusters. It would not make any changes in associated local kubernetes, app, etc.

  • Settings Icon: Settings Icon This will open settings dialog. It contains some selected cluster specific settings in addition to general app settings.

  • Configure Button: Configure Button This will open the configure dialog which is discussed later. If a configuration is already running then this button will be disabled and have a spinner in it.

  • Launch Button: Launch Button This button will open Ethereal Engine's default location in your browser as discussed later.

3.4. System Status

System Status

This section will show the current status of whether the system requirements are meet or not. On Windows, it will also show the status of prerequisites.

The status against each item will be displayed. You can find more details by hovering over Info Icon info icon. This info icon is useful when some item is not configured correctly.

Additionally, for some items you will see Fix Icon auto fix icon. Clicking this button will try to auto fix the problem. Though if it fails, you can try using configure dialog which is discussed later.

Usually, auto fix button should only be used if previously you were able to run the cluster successfully. Otherwise, use configure dialog.

3.5. Apps Status

Apps Status

This section will show the current status of all the apps required to run ethereal engine deployment.

3.6. Engine Status

Engine Status

This section will show the current status of various components of ethereal engine deployment in your local kubernetes distribution.

3.7. Logs

Logs

This section will show all the logs of current session. The logs are of the different actions being performed by control center and their output.

  • Download Button: Download Button This will download all displayed logs.

  • Clear Button: Clear Button This will clear all displayed logs.

4. Configure Cluster

On (cluster screen), if any of the status is not green tick then it means you need to run the configure script to fix them automatically. To do so use the Configure (Configure Button) button in the options panel. Following are the different sections of configure cluster dialog:

Its always recommended to clear your logs before running configure script in order to trace outputs easily.

4.1. Authentication

Configure Cluster - Authentication

In this step, you need to provide sudo password for linux terminal. This is because Control Center App will perform various actions on your system with admin privileges.

On Windows, this is the password of your WSL Ubuntu distribution's sudo user.

4.2. Configurations

Configure Cluster - Configurations

In this step, you will need to provide following information:

  • Engine Path: This is the location of ethereal engine source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Ops Path: This is the location of ethereal engine ops source code repo. If the path does not contain the source code, then it will be cloned by Control Center App.

    On Windows, the path must be inside WSL Ubuntu distribution.

  • Enable Ripple Stack: By default you should keep this option as off unless you want to have IPFS & rippled server running in your local K8s deployment.

  • Force DB Refresh: This will truncate database tables & repopulate them with seed data.

    If the database is empty, then Control Center App will itself force populate it.

4.3. Variables

Configure Cluster - Variables

In this step for most of the users, go with the default variable values and leave the text fields as it is.

For advanced setup, if you want to configure oAuth, S3 file storage, email, SMS support then you can provide variable values.

4.4. Summary

Configure Cluster - Summary

This step will show a summary of all the previous steps. User can review them before proceeding ahead.

Please make sure to read Note on this screen.

Afterwards, there are following option(s):

  • Configure: This will start the configuration script which will ensure things are setup. You can track output of various things in logs. Depending on your system and status of apps, it can take a while to setup things. As the configure script is executing, the Configure (Configure Button) button will be disabled and have a spinner in it.

    Once the script finished its execution, the cluster status will be automatically refreshed.

    If the configure script failed, pay close attention to last few lines of logs section. As it will contain the reason why script failed.

5. Launch Ethereal Engine

Launch Ethereal Engine

Once, everything is configured correctly and all ticks are green on config page (Cluster Screen) then you can click on Launch button in options panel. This button will open Ethereal Engine's default location in your browser.

Make sure to allow certificates as explained here.

6. Workloads

Workloads

This page will show current state of workloads for selected cluster. The workloads are mainly the k8s pods of various components of ethereal engine. In addition to options panel, following the sections of this screen:

6.1. Workload Tabs

Workload Tabs

This section allows to filter based on various workload types. Default tab will be All, which displays all workloads. The number below each tab's label will display the currently ready count followed by slash and then total count.

6.2. Workloads Table

Workloads Table

This section will display data based on selected workload tab. For each workload, it will contain pod name and other details. Hovering over a container's circle will display further details. Moreover, there is a Logs button to view kubernetes container logs as discussed in next section. Delete button will allow to remove the pod from current kubernetes distribution.

Additionally, there is refresh icon button on right top of this table. This will refresh/reload data being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval.

6.3. Workload Logs

Workload Logs

This section will by default display cluster logs. Though if user clicked Logs button as discussed in previous section, then the logs of that workload will be displayed. The cluster logs will then be displayed under Config log tab. User can toggle between these log tabs, while workload logs can be closed as well.

The download and clear icon button will perform actions based on selected log's tab. Additionally for workload logs, there is refresh icon button on right top of this section. This will refresh/reload logs being displayed. There is also an auto refresh drop down next to it, which will automatically perform refresh after selected interval.

Beside these icons there is also a container drop down through which user can select the workload's pod container for which logs are displayed.

7. Admin Dashboard

Admin Dashboard

Once, everything is configured correctly and all ticks are green on config page (Cluster Screen) then you can click on Admin button in navbar. This will show the admin dashboard of ethereal engine deployed in your local k8s cluster.

You can perform various actions from admin dashboard including installing projects, managing users, groups, locations, instances, resources, etc.

8. K8 Dashboard

K8 Dashboard

Once, your selected local k8s distribution (Microk8s or Minikube) has a green tick on config page (Cluster Screen) then you can click on K8 Dashboard button in navbar. This will show the k8s dashboard.

For MicroK8s, when you launch it for the first time then you will be asked regarding token configurations. You can use Skip button to pass through it.

K8 Dashboard Token

You can perform various actions from k8s dashboard including managing pods, jobs, deployments, services, etc.

9. IPFS

IPFS Web UI

If ripple stack is enabled and once, IPFS has a green tick on config page (Cluster Screen) then you can click on IPFS button in navbar. This will show the IPFS web UI.

You can view and manage various aspects of the IPFS running in your local cluster using this dashboard. IPFS is not required by default for engine, though for custom use cases it can be used.

10. Rippled CLI

Rippled CLI

If ripple stack is enabled and once, Rippled has a green tick on config page (Cluster Screen) then you can click on Rippled CLI button in navbar. This will show the Rippled CLI page.

You can run various commands against rippled server and view their outputs. Rippled is not required by default for engine, though for custom use cases it can be used.

11. Updating the App

Every time you launch control center app it will check for the latest version of the app. If there is an update, then it will prompt to update. Its always recommend to use the latest version of the app.

+ + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/tutorials/ethereal_control_center/index.html b/es/docs/host/devops_deployment/tutorials/ethereal_control_center/index.html new file mode 100644 index 000000000000..89cd8e9a7f0b --- /dev/null +++ b/es/docs/host/devops_deployment/tutorials/ethereal_control_center/index.html @@ -0,0 +1,16 @@ + + + + + +Control Center App | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/tutorials/index.html b/es/docs/host/devops_deployment/tutorials/index.html new file mode 100644 index 000000000000..02cff70836cc --- /dev/null +++ b/es/docs/host/devops_deployment/tutorials/index.html @@ -0,0 +1,16 @@ + + + + + +Tutorials | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/host/devops_deployment/upgrade_helm_deployment/index.html b/es/docs/host/devops_deployment/upgrade_helm_deployment/index.html new file mode 100644 index 000000000000..ef6fa2272d1e --- /dev/null +++ b/es/docs/host/devops_deployment/upgrade_helm_deployment/index.html @@ -0,0 +1,16 @@ + + + + + +Upgrading Helm Release | etherealengine + + + + +
+

Upgrading Helm Release

This guide will cover various sections regarding upgrading an existing helm deployment.

Getting Updated values.yaml File

Usually a helm release upgrade is required when changes are made in configuration of helm charts. To do so first thing required is value.yaml file of current configuration. If you already have an updated copy of this file then you can update the desired values and push the changes to helm deployment.

But for scenarios where multiple people are working same deployment, it becomes difficult to maintain updated values.yaml file. At anytime you can get the current version/snapshot of values.yaml file by running get values command:

helm get values [DEPLOYMENT_NAME]

i.e.

helm get values dev

You can save the output in a values.yaml file and update the required values.

Evaluating Difference in value.yaml & Deployed Charts

It become very handy if you can evaluate the differences between your local values.yaml file and current deployment. This way you can beforehand visualize the changes a helm upgrade is going to make. To do so first make sure you have helm diff plugin installed. You can install it by running:

helm plugin install https://github.com/databus23/helm-diff

Once helm diff plugin is installed then you can run following command:

helm diff upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --values [PATH_TO_VALUES_YAML]

i.e.

helm diff upgrade dev etherealengine/etherealengine --values ~/etherealengine-ops/values/dev.ethereal.values.yaml

This will print the output of differences between deployed helm release and changes in specified values.yaml file. Incase the output is empty, it means there is no difference/changes.

Upgrading Helm Deployment

Once the local values.yaml file is updated, it can be reflect to deployment using following commands:

helm upgrade [DEPLOYMENT_NAME] etherealengine/etherealengine --reuse-values -f [PATH_TO_VALUES_YAML]

i.e.

helm upgrade dev etherealengine/etherealengine --reuse-values -f ~/etherealengine-ops/values/dev.ethereal.values.yaml
+ + + + \ No newline at end of file diff --git a/es/docs/host/index.html b/es/docs/host/index.html new file mode 100644 index 000000000000..59d0aa41473a --- /dev/null +++ b/es/docs/host/index.html @@ -0,0 +1,16 @@ + + + + + +Ethereal for Hosts | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/docs/host/installation/advanced_setup/index.html b/es/docs/host/installation/advanced_setup/index.html new file mode 100644 index 000000000000..7159dfc34065 --- /dev/null +++ b/es/docs/host/installation/advanced_setup/index.html @@ -0,0 +1,46 @@ + + + + + +Advanced Setup | etherealengine + + + + +
+

Advanced Setup

If you want to setup Ethereal Engine docker instances, client, server, and/or +instance-server manually, follow these directions. The advanced setup is recommended +for all users, in order to understand more about everything that's going on.

1. Install your dependencies

cd path/to/etherealengine
npm install
npm run dev-docker
npm run dev-reinit

You should not need to use sudo in any case.

Error with mediasoup? https://mediasoup.org/documentation/v3/mediasoup/installation/

  • Check your version of python is up to date
  • Ensure your install path has no whitespaces

2. Make sure you have a mysql database installed and running -- our recommendation is Mariadb.

We've provided a docker container for easy setup:

cd scripts && sudo bash start-db.sh

This creates a Docker container of mariadb named etherealengine_db. You must have +docker installed on your machine for this script to work. +If you do not have Docker installed and do not wish to install it, you will have +to manually create a MariaDB server.

The default username is 'server', the default password is 'password', the +default database name is 'etherealengine', the default hostname is '127.0.0.1', and +the default port is 3306.

Seeing errors connecting to the local DB? Try shutting off your local firewall.

3. Open a new tab and start the Agones sidecar in local mode

cd scripts
sudo bash start-agones.sh

You can also go to vendor/agones/ and run

./sdk-server.linux.amd64 --local

If you are using a Windows machine, run

sdk-server.windows.amd64.exe --local

and for mac, run

./sdk-server.darwin.amd64 --local

4. Start the server in database seed mode

Several tables in the database need to be seeded with default values. +Run npm run dev-reinit or if on windows npm run dev-reinit-windows +After several seconds, there should be no more logging. +Some of the final lines should read like this:

Server Ready
Executing (default): SET FOREIGN_KEY_CHECKS = 1
Server EXIT

At this point, the database has been seeded.

5. Local file server configuration (Optional)

If the .env.local file you have has the line +STORAGE_PROVIDER=local +then the scene editor will save components, models, scenes, etc. locally +(as opposed to storing them on S3). You will need to start a local server +to serve these files, and make sure that .env.local has the line +LOCAL_STORAGE_PROVIDER="localhost:8642". +In a new tab, go to packages/server and run npm run serve-local-files. +This will start up http-server to serve files from packages/server/upload +on localhost:8642. +You may have to accept the invalid self-signed certificate for it in the browser; +see 'Allow local file http-server connection with invalid certificate' below.

6. Open two/three separate tabs and start the API server, instanceserver and client

In /packages/server, run npm run dev which will launch the api server, world server, media server and file server. +If you are not using instanceservers, you can instead run npm run dev-api-server in the api server. +In the final tab, go to /packages/client and run npm run dev. +If you are on windows you need to use npm run dev-windows instead of npm run dev.

7. In a browser, navigate to https://127.0.0.1:3000/location/default

The database seeding process creates a default empty location called 'default'. +It can be navigated to by going to 'https://127.0.0.1:3000/location/default'. +As of this writing, the cert provided in the ethereal engine package for local use is +not adequately signed. You can create signed certificates and replace the +default ones, but most developers just ignore the warnings. Browsers will throw +up warnings about going to insecure pages. You should be able to tell the browser +to ignore it, usually by clicking on some sort of 'advanced options' button or +link and then something along the lines of 'go there anyway'.

+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/basic_setup/index.html b/es/docs/host/installation/basic_setup/index.html new file mode 100644 index 000000000000..99c8e6a70d07 --- /dev/null +++ b/es/docs/host/installation/basic_setup/index.html @@ -0,0 +1,34 @@ + + + + + +Basic Setup | etherealengine + + + + +
+

Basic Setup

Installation

Getting up and running requires just a few steps, but this can be tricky, +depending on your platform and current environment. Please follow the directions +for your environment.

Pre-Install Checklist

  • Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less
  • Clone the repository
  • Install Node.js 16 or 18 (earlier versions not guaranteed to work)
  • Install Python >=3.6 + PIP, C++, and +other build tools. See the Mediasoup install instructions +for full details.
  • Install Docker
    • (Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's .env.local accordingly.

You should now be ready to follow the Quick Start instructions.

Clone the repository

A lot has changed during development, and our monorepo has gotten quite large. +To avoid cloning the entire thing, use this command:

git clone https://github.com/etherealengine/etherealengine --depth 1

Ensure you are running Node 16 or 18

The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions +are not guaranteed to work properly.

A version manager can be helpful for this:

Before running the engine, please check node --version +If you are using a node version below 16, please update or nothing will work. +You will know you are having issues if you try to install at root and are +getting dependency errors.

Docker is your friend

You don't need to use Docker, but it will make +your life much easier. +If you don't wish to use Docker, you will need to setup mariadb and redis on +your machine. You can find credentials in /scripts/docker-compose.yml

Quick Start

If you are lucky, this will just work. However, you may encounter some +issues. Make sure you are running Node 16, and check your dependencies.

cd path/to/etherealengine
cp .env.local.default .env.local
npm install
npm run dev-docker
npm run dev-reinit
npm run dev

Now run Ethereal Engine in browser by navigating to this link.

Accept Certificates

You'll have to tell your browser to ignore the insecure connections when you try to load the website.

  1. If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates.
  2. Open Developer tools in your browser by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I) and then go to the 'Console' tab.
  3. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab.
  4. You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.

Admin System and User Setup

You can administrate many features from the admin panel at https://localhost:3000/admin

To make a user an admin, open a page and open the profile menu. There is a button labelled Show User ID +which opens a text field with your userId. Paste it in and run the following command in +your terminal:

npm run make-user-admin -- --id={COPIED_USER_ID}

Example: +npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac

image

Alternate Method:

Look up in User table and change userRole to 'admin' +(It helps to use a graphical database explorer, we recommend beekeeperstudio.io)

Test user Admin privileges by going to /admin

Advanced Installation and Troubleshooting

If you run into any trouble with the Quick Start instructions:

+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/docker/index.html b/es/docs/host/installation/docker/index.html new file mode 100644 index 000000000000..c33040c15b71 --- /dev/null +++ b/es/docs/host/installation/docker/index.html @@ -0,0 +1,20 @@ + + + + + +Old Docker Instructions | etherealengine + + + + +
+

Old Docker Instructions

You can quickstart locally using docker, if you don't have node installed or +just want to test the latest.

Get local IP address

Use a tool like ifconfig to get your local IP address.

Start local databases

cd scripts
docker-compose up

When the logging stops, that indicates that the databases have been created and +are running.

Ctrl+c out of that, then from scripts run ./start-all-docker.sh +(This must be run every time you start your machine anew)

Build the image

Create an empty folder at the root called project-package-jsons and then run +the following command to build:

DOCKER_BUILDKIT=1 docker build -t etherealengine --build-arg MYSQL_USER=server \
--build-arg MYSQL_PASSWORD=password --build-arg MYSQL_HOST=127.0.0.1 \
--build-arg MYSQL_DATABASE=etherealengine --build-arg MYSQL_PORT=3304 \
--build-arg VITE_SERVER_HOST=localhost --build-arg VITE_SERVER_PORT=3030 \
--build-arg VITE_INSTANCESERVER_HOST=localhost --build-arg VITE_INSTANCESERVER_PORT=3031 \
--build-arg VITE_LOCAL_BUILD=true --build-arg CACHE_DATE="$(date)" --network="host" .

Run the server to seed the database, wait a couple minutes, then delete it

docker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "FORCE_DB_REFRESH=true" --network host etherealengine
docker logs server -f
-Wait for the line "Server Ready", then Ctrl+c out of the logs-
docker container stop server
docker container rm server

Run the images

docker run -d --name serve-local --env-file .env.local.default -e "SERVER_MODE=serve-local" --network host etherealengine
docker run -d --name server --env-file .env.local.default -e "SERVER_MODE=api" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine
docker run -d --name client --env-file .env.local.default -e "SERVER_MODE=client" --network host etherealengine
docker run -d --name world --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" --network host etherealengine
docker run -d --name channel --env-file .env.local.default -e "SERVER_MODE=realtime" -e "INSTANCESERVER_HOST=<local IP address>" -e "INSTANCESERVER_PORT=3032" --network host etherealengine

Delete containers, if you want to run a new build, or just get rid of them

docker container stop serve-local
docker container rm serve-local
docker container stop server
docker container rm server
docker container stop client
docker container rm client
docker container stop world
docker container rm world
docker container stop channel
docker container rm channel
+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/index.html b/es/docs/host/installation/index.html new file mode 100644 index 000000000000..3b84068a47e1 --- /dev/null +++ b/es/docs/host/installation/index.html @@ -0,0 +1,34 @@ + + + + + +Installation | etherealengine + + + + +
+

Installation

Getting up and running requires just a few steps, but this can be tricky, +depending on your platform and current environment. Please follow the directions +for your environment.

Pre-Install Checklist

  • Ensure you have at least 16GB of RAM - you may run into issues running the full development setup with less
  • Clone the repository
  • Install Node.js 16 or 18 (earlier versions not guaranteed to work)
  • Install Python >=3.6 + PIP, C++, and +other build tools. See the Mediasoup install instructions +for full details.
  • Install Docker
    • (Optionally) If you're NOT using docker, install MariaDB, Redis and MinIO manually and update repo's .env.local accordingly.

You should now be ready to follow the Quick Start instructions.

Clone the repository

A lot has changed during development, and our monorepo has gotten quite large. +To avoid cloning the entire thing, use this command:

git clone https://github.com/etherealengine/etherealengine --depth 1

Ensure you are running Node 16 or 18

The engine to date has only been confirmed to work perfectly with Node 16.x and 18.x. Earlier or later major versions +are not guaranteed to work properly.

A version manager can be helpful for this:

Before running the engine, please check node --version +If you are using a node version below 16, please update or nothing will work. +You will know you are having issues if you try to install at root and are +getting dependency errors.

Docker is your friend

You don't need to use Docker, but it will make +your life much easier. +If you don't wish to use Docker, you will need to setup mariadb and redis on +your machine. You can find credentials in /scripts/docker-compose.yml

Quick Start

If you are lucky, this will just work. However, you may encounter some +issues. Make sure you are running Node 16, and check your dependencies.

cd path/to/etherealengine
cp .env.local.default .env.local
npm install
npm run dev-docker
npm run dev-reinit
npm run dev

Now run Ethereal Engine in browser by navigating to this link.

Accept Certificates

You'll have to tell your browser to ignore the insecure connections when you try to load the website.

  1. If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates.
  2. Open Developer tools in your browser by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I) and then go to the 'Console' tab.
  3. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab.
  4. You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.

Admin System and User Setup

You can administrate many features from the admin panel at https://localhost:3000/admin

To make a user an admin, open a page and open the profile menu. There is a button labelled Show User ID +which opens a text field with your userId. Paste it in and run the following command in +your terminal:

npm run make-user-admin -- --id={COPIED_USER_ID}

Example: +npm run make-user-admin -- --id=c06b0210-453e-11ec-afc3-c57a57eeb1ac

image

Alternate Method:

Look up in User table and change userRole to 'admin' +(It helps to use a graphical database explorer, we recommend beekeeperstudio.io)

Test user Admin privileges by going to /admin

Advanced Installation and Troubleshooting

If you run into any trouble with the Quick Start instructions:

+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/install_troubleshooting/index.html b/es/docs/host/installation/install_troubleshooting/index.html new file mode 100644 index 000000000000..879e2ecec52d --- /dev/null +++ b/es/docs/host/installation/install_troubleshooting/index.html @@ -0,0 +1,36 @@ + + + + + +Troubleshooting | etherealengine + + + + +
+

Troubleshooting

Browser Debug

p key debug colliders view

Invalid Certificate errors in local environment

As of this writing, the cert provided in the ethereal engine package for local use +is not adequately signed. Browsers will throw up warnings about going to insecure pages. +You should be able to tell the browser to ignore it, usually by clicking on some sort +of 'advanced options' button or link and then something along the lines of 'go there anyway'.

Chrome sometimes does not show a clickable option on the warning. If so, just +type badidea or thisisunsafe when on that page. You don't enter that into the +address bar or into a text box, Chrome is just passively listening for those commands.

Allow instanceserver address connection via installing local Certificate Authority

For more detailed instructions check: https://github.com/FiloSottile/mkcert

Short version (common for development process on Ubuntu):

  1. Execute sudo apt install libnss3-tools
  2. Execute brew install mkcert (if you don't have brew, check it's page: https://brew.sh/)
  3. Execute mkcert --install
  4. Navigate to ./certs folder
  5. Execute mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1

Allow local file http-server connection with invalid certificate

Open the developer tools in your browser by pressing Ctrl+Shift+i at the +same time. Go to the 'Console' tab and look at the message history. If there are +red errors that say something like +GET https://127.0.0.1:3030/socket.io/?EIO=3&transport=polling&t=NXlZLTa net::ERR_CERT_AUTHORITY_INVALID, +then right-click that URL, then select 'Open in new tab', and accept the invalid certificate.

Allow instanceserver address connection with invalid certificate

The instanceserver functionality is hosted on an address other than 127.0.0.1 in the local +environment. Accepting an invalid certificate for 127.0.0.1 will not apply to this address. +Open the dev console for Chrome/Firefox by pressing Ctrl+Shift+i simultaneously, and +go to the Console or Network tabs.

If you see errors about not being able to connect to +something like https://192.168.0.81:3031/socket.io/?location=<foobar>, right click on +that URL and open it in a new tab. You should again get a warning page about an invalid +certificate, and you again need to allow it.

AccessDenied connecting to mariadb

Make sure you don't have another instance of mariadb running on port 3306

lsof -i :3306

On Linux, you can also check if any processes are running on port 3306 with +sudo netstat -utlp | grep 3306 +The last column should look like <ID>/<something +You can kill any running process with sudo kill <ID>

Error: listen EADDRINUSE :::3030

Check which process is using port 3030 and kill

killall -9 node 

Or

lsof -i :3030
kill -3 <proccessIDfromPreviousCommand>

'CORS error' in terminal

Try accessing the page using https://localhost:3000 +instead of https://127.0.0.1:3000

Default blank screen

Try typing “thisisunsafe” or "iknowwhatiamdoing" then reload page

Instanceserver or resource loading error?

Open dev console, click on the GET link in new tab and accept certificate by +typing thisisunsafe” or "iknowwhatiamdoing" then reload original page

To install a new package for editor react components in monorepo

Type in terminal

     npm i <packagename> -w @etherealengine/editor

Using Local Storage instead of MinIO

Currently MinIO is used as default storage for local development. If you want to use local storage then do following steps:

  • set VITE_FILE_SERVER to the commented values under # Use following value for local file server and comment out the values above it.
  • set STORAGE_PROVIDER to local

Accessing MinIO S3 storage provider running in local docker

Using MinIO Console:

  • When MinIO contain is running in your docker, navigate to https://localhost:9001/ in your browser.

    Make sure to accept invalid certificate warning.

  • Login using username as server and password as password.

    You can find these credentials in scripts/docker-compose.yml as MINIO_ROOT_USER & MINIO_ROOT_PASSWORD

Using S3 Browser (Windows Only):

  • Download & install S3 Browser from https://s3browser.com/download.aspx.
  • Launch and connect using following details:
    • Account Type: S3 Compatible Storage
    • REST Endpoint: 127.0.0.1:9000
    • Access Key ID: server
    • Secret Access Key: password
    • Use secure transfer (SSL/TLS): Check / On / True

Clear all data from MinIO S3 storage provider running in local docker

Run following commands in your terminal:

  docker container stop etherealengine_minio_s3
docker container rm etherealengine_minio_s3
docker container prune --force
docker volume prune --force
npm run dev-docker
npm run dev-reinit

DB not seeding routes (E.g. Error: No project installed- please contact site admin)

Try

  npm run dev-reinit 

or

  docker container stop etherealengine_db
docker container rm etherealengine_db
docker container prune --force
npm run dev-docker
npm run dev-reinit

Weird issues with your database?

Try

npm run dev-reinit

Or if on windows

npm run dev-reinit-windows
+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/mac_os_x/index.html b/es/docs/host/installation/mac_os_x/index.html new file mode 100644 index 000000000000..423b28423688 --- /dev/null +++ b/es/docs/host/installation/mac_os_x/index.html @@ -0,0 +1,23 @@ + + + + + +Installing on Mac OS X | etherealengine + + + + +
+

Installing on Mac OS X

  1. Go to the root and run
npm install
npm run dev-docker
npm run dev-reinit

Or if you are on a M1 based Mac

(Recommended) +1) Duplicate the Terminal app, and configure it to run in Rosetta +2) Run the above in Rosetta Terminal

(Not recommended)

yarn install

This is because on Apple chips the node-darwin sometimes doesn't get installed +properly and by using yarn it fixes the issue.

  1. Have docker started in the background and then in the terminal type
npm run dev

This will open the mariaDB and SQL scripts on the docker and will start the servers

  1. To make sure your environment is set and running properly just go to +https://localhost:3000/location/default and you should be able to walk around an empty 3D scene
Note : Make sure you are on Node >= 16 and have docker running. 

Troubleshooting Mac

  • If you find issues on your terminal that says that access-denied for user +server@localhost then you can use this command
brew services stop mysql
  • If you find issue on your terminal that says +An unexpected error occurred: "expected workspace package +while using yarn then you can use this command in your terminal
yarn policies set-version 1.18.0

As yarn > 1.18 sometimes doesn't work properly with lerna.

+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/opensearch/index.html b/es/docs/host/installation/opensearch/index.html new file mode 100644 index 000000000000..3e5456cb8aad --- /dev/null +++ b/es/docs/host/installation/opensearch/index.html @@ -0,0 +1,16 @@ + + + + + +Logging with Opensearch on Docker | etherealengine + + + + +
+

Logging with Opensearch on Docker

If you want to quickstart with detailed logging using opensearch, Please follow this guide.

Setup Opensearch on Docker locally

Pull OpenSearch Images

OpenSearch

docker pull opensearchproject/opensearch:latest

OpenSearch Dashboard

docker pull opensearchproject/opensearch-dashboards:latest

Start Opensearch Containers

OpenSearch

docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" -e "plugins.security.disabled=true" opensearchproject/opensearch:latest 

OpenSearch Dashboard

docker run -it -d --network="host" -e "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true" opensearchproject/opensearch-dashboards:latest

Verify if the containers are up & running

  • Send a request to port 9200
    curl http://127.0.0.1:9200
  • List Indices through curl
    curl -X GET "http://127.0.0.1:9200/_cat/indices?v"
  • Create Indices through Curl
    curl -X PUT "http://127.0.0.1:9200/your_index_name"
  • Delete Index
    curl --location --request DELETE 'http://127.0.0.1:9200/index_name'
  • Fetch logs for an index_name
    curl --location --request GET 'http://127.0.0.1:9200/ethereal/_search' \
--header 'Content-Type: application/json' \
--data '{
"query": {
"match_all": {}
},
"size": 10000
}'

Enable Client Logging

Set VITE_FORCE_CLIENT_LOG_AGGREGATE to true to enable client log aggregation

VITE_FORCE_CLIENT_LOG_AGGREGATE=true

Enable Server Logging

Set DISABLE_SERVER_LOG=false to false to enable server log aggregation

DISABLE_SERVER_LOG=false

Note: These changes in the .env.local file will ensure proper communication with OpenSearch and enable client and server log aggregation

+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/running_on_static_IP/index.html b/es/docs/host/installation/running_on_static_IP/index.html new file mode 100644 index 000000000000..ca0d4c96f89e --- /dev/null +++ b/es/docs/host/installation/running_on_static_IP/index.html @@ -0,0 +1,26 @@ + + + + + +Running on Static IP under WSL2 | etherealengine + + + + +
+

Running on Static IP under WSL2

Follow these steps to run the engine on a static IP instead of localhost. In +most cases you should be able to simply access the engine using the public IP +assigned to your device, but if you run into any issues or if you are running +the stack on WSL2 then you can refer to the following directions.

  1. Replace all localhost values with the static IP you want to run the stack on +in your .env.local file.
  2. Open a PowerShell terminal as admin. And run the wsl2-port-forwarding.ps1 +script present under /scripts directory. +Note: Make sure all of the required ports are present in ports array of the +wsl2-port-forwarding.ps1 script.
  3. And now just run the engine as you normally would and everything should be +accessible over the static IP.
  4. If you get any errors related to localhost:8642, then make sure that none of +the assets in your scene have been saved localhost path. If there are then +replace localhost with the static IP in the respective asset's path too.
+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/windows/index.html b/es/docs/host/installation/windows/index.html new file mode 100644 index 000000000000..0481db5bc489 --- /dev/null +++ b/es/docs/host/installation/windows/index.html @@ -0,0 +1,17 @@ + + + + + +Installing on Windows 10+ | etherealengine + + + + +
+

Installing on Windows 10+

  1. Install python 3 and add python installation directory path to 'PATH' env variable.
  2. Install node js
  3. Install Visual studio community edition with build tools.

    Note: If mediasoup is not installed properly then modify Visual studio setup to add c++ and Node.js support.

  4. Add path of MSbuild.exe (which is present in visual studio folder) into 'path' env variable (for example: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin)
  5. Make sure to install all windows prerequisites for mediasoup as mentioned on: https://mediasoup.org/documentation/v3/mediasoup/installation/#windows
  6. Install all dependencies using npm i.
  7. If error persists then check for typos in environment variables.
  8. If you are on Windows, you can use docker-compose to start the scripts/docker-compose.yml file, or install mariadb and copy credentials (database name, username, password) from docker-compose or .env.local -- you will need to create an empty database with the matching name.

./start-db.sh only needs to be run once. If the docker image has stopped, start it again with:

docker container start etherealengine_db
  1. Check your WSL config for any incorrect networking settings. +https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network
+ + + + \ No newline at end of file diff --git a/es/docs/host/installation/windows_wsl/index.html b/es/docs/host/installation/windows_wsl/index.html new file mode 100644 index 000000000000..5fb19156973f --- /dev/null +++ b/es/docs/host/installation/windows_wsl/index.html @@ -0,0 +1,20 @@ + + + + + +Installing on Windows with WSL2 | etherealengine + + + + +
+

Installing on Windows with WSL2

This guide is currently tested on Windows 10 (22H2) and Windows 11.

Install Windows Subsystem for Linux (WSL).

Remember to run Powershell in Administrator mode either by right clicking and selecting 'Run as administrator' or by typing PowerShell in 'Run' dialog box of Windows and pressing Ctrl+Shift+Enter key combination.

Install Ubuntu distribution of Linux by executing the command: +wsl --install --distribution Ubuntu +or +Install Ubuntu distribution of Linux from Microsoft Store by using guide here.

Alternatively, you can follow these instructions as well:

Once WSL is installed, make sure to:

Install Docker Desktop

Install docker desktop with WSL 2 backend. You can find the instructions here.

Once docker desktop is installed and running make sure to enable your WSL distribution. You can do so from Docker Desktop App by visiting Settings > Resources > WSL Integration. Enable integration with Ubuntu. Make sure to hit 'Apply & Restart'.

Docker Desktop WSL Distro

Install Node.

Run Powershell in Administrator mode. Run Ubuntu using command : wsl. After logging on run the following command: cd ~/ to ensure that the installation of Node and other packages mentioned below is done in Ubuntu.

In your WSL Ubuntu terminal, if node (node --version) isn't already installed on your machine. You can do so by first installing nvm by running following commands:

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source ~/.profile

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

You can verify nvm by using nvm --version command. Afterwards, install Node (version between 16.0 and 18.0 both inclusive) by using:

nvm install --lts

You can verify node version by using node --version command.

Install Python 3

In your WSL Ubuntu terminal, if python 3 (pip3 --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y python3-pip

You can verify python3 by using python3 --version command.

Install Make

In your WSL Ubuntu terminal, if make (make --version) isn't already installed on your machine. You can do so by running following commands:

sudo apt-get update -y
sudo apt-get install -y build-essential

You can verify make by using make --version command.

Clone Ethereal Engine repo to your local machine

Clone Ethereal Engine repo on your machine by running following command in WSL Ubuntu terminal. You can check the directory in which you are sitting by the command: pwd

git clone https://github.com/etherealengine/etherealengine --depth 1

Change directory to the location where etherealengine repo is cloned cd etherealengine +If .env.local file does not exist in the root of your repo folder then create it by duplicating .env.local.default. Command: cp .env.local.default .env.local

Afterwards, install npm packages using:

npm install

Note: If you face issue related to mediasoup while doing npm install. Then remove the mediasoup package from packages/instanceserver/package.json file of Ethereal Engine source code. And run npm install again. Afterwards, run:

npm install mediasoup@3 -w @etherealengine/instanceserver

Initialize MariaDB server

If you are running the engine for the first time then you will need to initialize the database with tables and data. You can do so by running:

npm run dev-reinit

Start Engine Stack

You can run Ethereal Engine stack by running:

npm run dev

Now run Ethereal Engine in browser by navigating to this link.

Accept Certificates

You'll have to tell your browser to ignore the insecure connections when you try to load the website.

  1. If it keeps displaying 'loading routes' progress for a long time, it is due to the fact that you have to allow certificates.
  2. Open Developer tools in your browser by clicking the side menu with three dots, then More tools > Developer tools (or use Ctrl+Shift+I) and then go to the 'Console' tab.
  3. You will see some errors in URL address starting with 'wss'. Replace 'wss' with 'https' and open it in new tab. Accept the certificate and reload your Ethereal Engine tab.
  4. You will see some errors in URL address starting with 'https://localhost:9000'. Open of the that URL and accept the certificate afterwards reload your Ethereal Engine tab.
+ + + + \ No newline at end of file diff --git a/es/docs/index.html b/es/docs/index.html new file mode 100644 index 000000000000..52b7060ddf90 --- /dev/null +++ b/es/docs/index.html @@ -0,0 +1,22 @@ + + + + + +Overview | etherealengine + + + + +
+

Ethereal Engine

Ethereal Engine is a free, open, full-stack MMO engine that anyone can run for +any reason - to host events, make games, showcase art, or just to provide a space for your community. There are plenty of platforms on which you can spend a bit to have a world, but you can't be in complete control of the experience or customise it from the ground up.

When the Ethereal Engine stack is deployed, that stack is sovereign, open and cross +platform by default. Users can create any kind of game or experience with no limits. +With the tech that's being built now, users will be able to seamlessly travel +through portals from any worlds to any other world, on different servers, and have all +their data and identity travel with them.

This technology is for everyone, but especially people who want to build or +belong to a community.

WebXR Engine

The core engine is the heart of Ethereal Engine. Based around the WebXR spec, brought to life with libraries such as threejs, bitecs, rapier.js, Mediasoup WebRTC, reactjs & hookstatejs. With the latest understanding of Data-Oriented Design, ECS and Event-Sourcing paradigms, we have put together a robust MMO XR framework that rivals AAA capabilities, quality and speed.

On The Web

Built for the web, Ethereal Engine providers a fully customisable and clean UI that works in both immersive and non-immersive contexts, as well as an administration panel for full control of deployment, locations, projects, avatars, custom routes & more.

Deployment Stack

Running on the backend is a state of the art fullstack framework, template & deployment pipeline using kubernetes, docker, agones, openmatch & feathersjs. The result is a fully customisable and scalable web app.

Ethereal Studio

The Studio sits on top of the engine, as a heavily modified version of Mozilla Hubs' Spoke editor. It has been transformed with the engine and the web app to provide a fast and comprehensive Content Management System, file browser, cloud edge caching, content pipeline tools and other creator tools.

Project API

The Project API is the core of what makes Ethereal Engine shine - the ability to load your own scenes, assets & code with a click of a button. Using github, we allow users to have fully version controlled access to extend the base functionality. You can see examples of the Project API in action here and here

Stack Overview

+ + + + \ No newline at end of file diff --git a/es/img/favicon.ico b/es/img/favicon.ico new file mode 100644 index 000000000000..72850fe8a5bd Binary files /dev/null and b/es/img/favicon.ico differ diff --git a/es/img/logo.png b/es/img/logo.png new file mode 100644 index 000000000000..b923d71677c3 Binary files /dev/null and b/es/img/logo.png differ diff --git a/es/img/logo.svg b/es/img/logo.svg new file mode 100644 index 000000000000..0cde304526e5 --- /dev/null +++ b/es/img/logo.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/es/img/undraw_docusaurus_mountain.svg b/es/img/undraw_docusaurus_mountain.svg new file mode 100644 index 000000000000..cb4c3eef6733 --- /dev/null +++ b/es/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/es/img/undraw_docusaurus_react.svg b/es/img/undraw_docusaurus_react.svg new file mode 100644 index 000000000000..744948c593fb --- /dev/null +++ b/es/img/undraw_docusaurus_react.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/es/img/undraw_docusaurus_tree.svg b/es/img/undraw_docusaurus_tree.svg new file mode 100644 index 000000000000..4ad0c198aaba --- /dev/null +++ b/es/img/undraw_docusaurus_tree.svg @@ -0,0 +1,93 @@ +docu_tree + + \ No newline at end of file diff --git a/es/index.html b/es/index.html new file mode 100644 index 000000000000..c728b4ab34cf --- /dev/null +++ b/es/index.html @@ -0,0 +1,16 @@ + + + + + +etherealengine | etherealengine + + + + +
+

etherealengine

An open source solution for hosting, creating and developing immersive social spaces, built on top of WebXR, React & Feathers.

Ethereal Engine Embraces The Web

Ethereal Engine Embraces The Web

Reach everyone. No app stores. Open Source.
Mobile - Desktop - Headsets

Focus On What Matters

Focus On What Matters

A comprehensive studio, pipeline tools, endless immersive features.

Built On Well Known Web Frameworks

Built On Well Known Web Frameworks

Power your experiences immediately with React, Threejs, Feathers, Kubernetes, bitECS

+ + + + \ No newline at end of file diff --git a/es/markdown-page/index.html b/es/markdown-page/index.html new file mode 100644 index 000000000000..2493d0811ca6 --- /dev/null +++ b/es/markdown-page/index.html @@ -0,0 +1,16 @@ + + + + + +Markdown page example | etherealengine + + + + +
+

Markdown page example

You don't need React to write simple standalone pages.

+ + + + \ No newline at end of file diff --git a/es/opensearch.xml b/es/opensearch.xml new file mode 100644 index 000000000000..6a728f5673c8 --- /dev/null +++ b/es/opensearch.xml @@ -0,0 +1,11 @@ + + + etherealengine + Search etherealengine + UTF-8 + https://etherealengine.github.io/etherealengine-docs/es/img/favicon.ico + + + https://etherealengine.github.io/etherealengine-docs/es/ + \ No newline at end of file diff --git a/es/search/index.html b/es/search/index.html new file mode 100644 index 000000000000..9233bba91c52 --- /dev/null +++ b/es/search/index.html @@ -0,0 +1,16 @@ + + + + + +Búsqueda en la documentación | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/es/sitemap.xml b/es/sitemap.xml new file mode 100644 index 000000000000..d3221afbc3ac --- /dev/null +++ b/es/sitemap.xml @@ -0,0 +1 @@ +https://etherealengine.github.io/etherealengine-docs/es/markdown-pageweekly0.5https://etherealengine.github.io/etherealengine-docs/es/searchweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/avatars/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/concepts/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/concepts/editor_scenes_locationsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/actions_event_sourcingweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/behave_graphweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/ecsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/networkingweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/projects_overviewweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/development/state_managementweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/importing_assets/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/studio/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/debuggingweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/debugging_deployed_instanceserversweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/debugging_device_wslweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/reasonable_codeweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/test_driven_developmentweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/testing/testing_introweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/tutorials/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unity_bridgeweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/creator/tutorials/ethereal_engine/unreal_bridgeweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/guest/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/Admin_Dashboard/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/AWS_setupweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/database_migrationsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/docker_desktopweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/installing_projectsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/managing_remote_kubernetesweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/microk8s_linuxweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/microk8s_windowsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/minikubeweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/release_helm_chartweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/setup_github_oauth_for_projectsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/tutorials/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_startedweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/devops_deployment/upgrade_helm_deploymentweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/weekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/advanced_setupweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/basic_setupweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/dockerweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/install_troubleshootingweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/mac_os_xweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/opensearchweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/running_on_static_IPweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/windowsweekly0.5https://etherealengine.github.io/etherealengine-docs/es/docs/host/installation/windows_wslweekly0.5https://etherealengine.github.io/etherealengine-docs/es/weekly0.5 \ No newline at end of file diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 000000000000..72850fe8a5bd Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 000000000000..b923d71677c3 Binary files /dev/null and b/img/logo.png differ diff --git a/img/logo.svg b/img/logo.svg new file mode 100644 index 000000000000..0cde304526e5 --- /dev/null +++ b/img/logo.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/undraw_docusaurus_mountain.svg b/img/undraw_docusaurus_mountain.svg new file mode 100644 index 000000000000..cb4c3eef6733 --- /dev/null +++ b/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/undraw_docusaurus_react.svg b/img/undraw_docusaurus_react.svg new file mode 100644 index 000000000000..744948c593fb --- /dev/null +++ b/img/undraw_docusaurus_react.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/undraw_docusaurus_tree.svg b/img/undraw_docusaurus_tree.svg new file mode 100644 index 000000000000..4ad0c198aaba --- /dev/null +++ b/img/undraw_docusaurus_tree.svg @@ -0,0 +1,93 @@ +docu_tree + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000000..b16134be1714 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + +etherealengine | etherealengine + + + + +
+

etherealengine

An open source solution for hosting, creating and developing immersive social spaces, built on top of WebXR, React & Feathers.

Ethereal Engine Embraces The Web

Ethereal Engine Embraces The Web

Reach everyone. No app stores. Open Source.
Mobile - Desktop - Headsets

Focus On What Matters

Focus On What Matters

A comprehensive studio, pipeline tools, endless immersive features.

Built On Well Known Web Frameworks

Built On Well Known Web Frameworks

Power your experiences immediately with React, Threejs, Feathers, Kubernetes, bitECS

+ + + + \ No newline at end of file diff --git a/markdown-page/index.html b/markdown-page/index.html new file mode 100644 index 000000000000..b062d7a94d2e --- /dev/null +++ b/markdown-page/index.html @@ -0,0 +1,16 @@ + + + + + +Markdown page example | etherealengine + + + + +
+

Markdown page example

You don't need React to write simple standalone pages.

+ + + + \ No newline at end of file diff --git a/opensearch.xml b/opensearch.xml new file mode 100644 index 000000000000..4efcf0cd5321 --- /dev/null +++ b/opensearch.xml @@ -0,0 +1,11 @@ + + + etherealengine + Search etherealengine + UTF-8 + https://etherealengine.github.io/etherealengine-docs/img/favicon.ico + + + https://etherealengine.github.io/etherealengine-docs/ + \ No newline at end of file diff --git a/search/index.html b/search/index.html new file mode 100644 index 000000000000..0ebc01f30290 --- /dev/null +++ b/search/index.html @@ -0,0 +1,16 @@ + + + + + +Search the documentation | etherealengine + + + + + + + + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000000..418b8adf322b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://etherealengine.github.io/etherealengine-docs/markdown-pageweekly0.5https://etherealengine.github.io/etherealengine-docs/searchweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/avatars/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/concepts/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/concepts/editor_scenes_locationsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/actions_event_sourcingweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/behave_graphweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/ecsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/networkingweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/projects_overviewweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/development/state_managementweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/importing_assets/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/studio/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/debuggingweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/debugging_deployed_instanceserversweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/debugging_device_wslweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/reasonable_codeweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/test_driven_developmentweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/testing/testing_introweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/tutorials/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/tutorials/ethereal_engine/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unity_bridgeweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/creator/tutorials/ethereal_engine/unreal_bridgeweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/guest/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/Admin_Dashboard/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/AWS_setupweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/database_migrationsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/docker_desktopweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/installing_projectsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/managing_remote_kubernetesweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/microk8s_linuxweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/microk8s_windowsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/minikubeweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/release_helm_chartweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/setup_github_oauth_for_projectsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/tutorials/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/tutorials/ethereal_control_center/getting_startedweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/devops_deployment/upgrade_helm_deploymentweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/weekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/advanced_setupweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/basic_setupweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/dockerweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/install_troubleshootingweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/mac_os_xweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/opensearchweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/running_on_static_IPweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/windowsweekly0.5https://etherealengine.github.io/etherealengine-docs/docs/host/installation/windows_wslweekly0.5https://etherealengine.github.io/etherealengine-docs/weekly0.5 \ No newline at end of file