diff --git a/.github/workflows/code_quality_check.yml b/.github/workflows/code_quality_check.yml new file mode 100644 index 0000000000..b864e81bf7 --- /dev/null +++ b/.github/workflows/code_quality_check.yml @@ -0,0 +1,21 @@ +name: Code Quality Check + +on: + pull_request: + branches: [main] + + workflow_dispatch: + +jobs: + prettier: + name: Prettier + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "20" + - run: npm install + working-directory: ./launcher + - run: npm run format:check + working-directory: ./launcher diff --git a/.vscode/settings.json b/.vscode/settings.json index 3150ee826b..bf29f43a4c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,9 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "vue3snippets.enable-compile-vue-file-on-did-save-code": true, "javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false, "typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false diff --git a/launcher/.prettierignore b/launcher/.prettierignore new file mode 100644 index 0000000000..cd4b6bfb2e --- /dev/null +++ b/launcher/.prettierignore @@ -0,0 +1,8 @@ +**/.git +**/.svn +**/.hg +**/node_modules +**/coverage +**/dist +**/dist_electron +package-lock.json \ No newline at end of file diff --git a/launcher/.prettierrc.json b/launcher/.prettierrc.json index 9a352ee54c..4bd9108e18 100755 --- a/launcher/.prettierrc.json +++ b/launcher/.prettierrc.json @@ -2,6 +2,6 @@ "semi": true, "singleQuote": false, "tabWidth": 2, - "printWidth": 120, + "printWidth": 140, "useTabs": false -} \ No newline at end of file +} diff --git a/launcher/customsign.js b/launcher/customsign.js index 08ce5e7b15..d75c893a26 100644 --- a/launcher/customsign.js +++ b/launcher/customsign.js @@ -1,13 +1,8 @@ -'use strict'; +"use strict"; // custom sign script calling digicerts keytool from out of the electron-builder -exports.default = async function(configuration) { - - if(configuration.path){ - - require("child_process").execSync( - `smctl sign --keypair-alias=${process.env.KEYPAIR_ALIAS} --input "${String(configuration.path)}"` - ); - - } - }; \ No newline at end of file +exports.default = async function (configuration) { + if (configuration.path) { + require("child_process").execSync(`smctl sign --keypair-alias=${process.env.KEYPAIR_ALIAS} --input "${String(configuration.path)}"`); + } +}; diff --git a/launcher/package.json b/launcher/package.json index 9815efb45e..adbfa77583 100755 --- a/launcher/package.json +++ b/launcher/package.json @@ -21,7 +21,8 @@ "lint:fix": "eslint --ext .js,.vue --ignore-path ../.gitignore --fix src", "stereum": "concurrently \"npm:electron:serve\" \"npm:watch:css\"", "backend:watch": "nodemon --watch 'src/backend' --exec 'npm run electron:serve'", - "format": "prettier . --write" + "format": "prettier . --write", + "format:check": "prettier . --check" }, "dependencies": { "@headlessui/vue": "^1.7.16", diff --git a/launcher/public/index.html b/launcher/public/index.html index 32966587ee..6d28892e4e 100755 --- a/launcher/public/index.html +++ b/launcher/public/index.html @@ -10,8 +10,8 @@
diff --git a/launcher/public/output.css b/launcher/public/output.css index 6ad9d34d79..9cd44e24db 100755 --- a/launcher/public/output.css +++ b/launcher/public/output.css @@ -13,7 +13,7 @@ ::before, ::after { -webkit-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; /* 1 */ border-width: 0; /* 2 */ @@ -25,7 +25,7 @@ ::before, ::after { - --tw-content: ''; + --tw-content: ""; } /* @@ -47,12 +47,12 @@ html, -moz-tab-size: 4; /* 3 */ -o-tab-size: 4; - tab-size: 4; + tab-size: 4; /* 3 */ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ -webkit-font-feature-settings: normal; - font-feature-settings: normal; + font-feature-settings: normal; /* 5 */ font-variation-settings: normal; /* 6 */ @@ -93,7 +93,7 @@ Add the correct text decoration in Chrome, Edge, and Safari. abbr:where([title]) { -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; + text-decoration: underline dotted; } /* @@ -142,7 +142,7 @@ pre { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ -webkit-font-feature-settings: normal; - font-feature-settings: normal; + font-feature-settings: normal; /* 2 */ font-variation-settings: normal; /* 3 */ @@ -207,7 +207,7 @@ textarea { font-family: inherit; /* 1 */ -webkit-font-feature-settings: inherit; - font-feature-settings: inherit; + font-feature-settings: inherit; /* 1 */ font-variation-settings: inherit; /* 1 */ @@ -242,9 +242,9 @@ select { */ button, -input:where([type='button']), -input:where([type='reset']), -input:where([type='submit']) { +input:where([type="button"]), +input:where([type="reset"]), +input:where([type="submit"]) { -webkit-appearance: button; /* 1 */ background-color: transparent; @@ -291,7 +291,7 @@ Correct the cursor style of increment and decrement buttons in Safari. 2. Correct the outline style in Safari. */ -[type='search'] { +[type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; @@ -384,28 +384,32 @@ textarea { 2. Set the default placeholder color to the user's configured gray 400 color. */ -input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { opacity: 1; /* 1 */ color: #9ca3af; /* 2 */ } -input::-moz-placeholder, textarea::-moz-placeholder { +input::-moz-placeholder, +textarea::-moz-placeholder { opacity: 1; /* 1 */ color: #9ca3af; /* 2 */ } -input:-ms-input-placeholder, textarea:-ms-input-placeholder { +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { opacity: 1; /* 1 */ color: #9ca3af; /* 2 */ } -input::-ms-input-placeholder, textarea::-ms-input-placeholder { +input::-ms-input-placeholder, +textarea::-ms-input-placeholder { opacity: 1; /* 1 */ color: #9ca3af; @@ -473,12 +477,14 @@ video { display: none; } -*{ +* { scrollbar-color: initial; scrollbar-width: initial; } -*, ::before, ::after{ +*, +::before, +::after { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; @@ -488,19 +494,19 @@ video { --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / 0.5); @@ -508,31 +514,31 @@ video { --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::-ms-backdrop{ + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::-ms-backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; @@ -542,19 +548,19 @@ video { --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / 0.5); @@ -562,31 +568,31 @@ video { --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::backdrop{ + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; @@ -596,19 +602,19 @@ video { --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / 0.5); @@ -616,28 +622,28 @@ video { --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; } ::-webkit-scrollbar { @@ -657,41 +663,41 @@ video { background-color: transparent; } -.container{ +.container { width: 100%; } -@media (min-width: 640px){ - .container{ +@media (min-width: 640px) { + .container { max-width: 640px; } } -@media (min-width: 768px){ - .container{ +@media (min-width: 768px) { + .container { max-width: 768px; } } -@media (min-width: 1024px){ - .container{ +@media (min-width: 1024px) { + .container { max-width: 1024px; } } -@media (min-width: 1280px){ - .container{ +@media (min-width: 1280px) { + .container { max-width: 1280px; } } -@media (min-width: 1536px){ - .container{ +@media (min-width: 1536px) { + .container { max-width: 1536px; } } -.sr-only{ +.sr-only { position: absolute; width: 1px; height: 1px; @@ -703,4585 +709,4625 @@ video { border-width: 0; } -.pointer-events-none{ +.pointer-events-none { pointer-events: none; } -.visible{ +.visible { visibility: visible; } -.invisible{ +.invisible { visibility: hidden; } -.static{ +.static { position: static; } -.fixed{ +.fixed { position: fixed; } -.absolute{ +.absolute { position: absolute; } -.relative{ +.relative { position: relative; } -.sticky{ +.sticky { position: sticky; } -.inset-0{ +.inset-0 { inset: 0px; } -.inset-x-0{ +.inset-x-0 { left: 0px; right: 0px; } -.inset-x-20{ +.inset-x-20 { left: 5rem; right: 5rem; } -.inset-x-6{ +.inset-x-6 { left: 1.5rem; right: 1.5rem; } -.inset-y-0{ +.inset-y-0 { top: 0px; bottom: 0px; } -.-bottom-2{ +.-bottom-2 { bottom: -0.5rem; } -.-bottom-3{ +.-bottom-3 { bottom: -0.75rem; } -.-bottom-8{ +.-bottom-8 { bottom: -2rem; } -.-left-\[1px\]{ +.-left-\[1px\] { left: -1px; } -.-right-2{ +.-right-2 { right: -0.5rem; } -.-right-24{ +.-right-24 { right: -6rem; } -.-right-4{ +.-right-4 { right: -1rem; } -.-right-5{ +.-right-5 { right: -1.25rem; } -.-top-11{ +.-top-11 { top: -2.75rem; } -.-top-20{ +.-top-20 { top: -5rem; } -.-top-8{ +.-top-8 { top: -2rem; } -.-top-\[90px\]{ +.-top-\[90px\] { top: -90px; } -.bottom-0{ +.bottom-0 { bottom: 0px; } -.bottom-0\.5{ +.bottom-0\.5 { bottom: 0.125rem; } -.bottom-1{ +.bottom-1 { bottom: 0.25rem; } -.bottom-2{ +.bottom-2 { bottom: 0.5rem; } -.bottom-20{ +.bottom-20 { bottom: 5rem; } -.bottom-4{ +.bottom-4 { bottom: 1rem; } -.bottom-\[3rem\]{ +.bottom-\[3rem\] { bottom: 3rem; } -.bottom-\[8px\]{ +.bottom-\[8px\] { bottom: 8px; } -.end-0{ +.end-0 { inset-inline-end: 0px; } -.end-1{ +.end-1 { inset-inline-end: 0.25rem; } -.end-2{ +.end-2 { inset-inline-end: 0.5rem; } -.left-0{ +.left-0 { left: 0px; } -.left-1{ +.left-1 { left: 0.25rem; } -.left-1\/2{ +.left-1\/2 { left: 50%; } -.left-12{ +.left-12 { left: 3rem; } -.left-14{ +.left-14 { left: 3.5rem; } -.left-3{ +.left-3 { left: 0.75rem; } -.left-\[1\.3rem\]{ +.left-\[1\.3rem\] { left: 1.3rem; } -.left-\[17rem\]{ +.left-\[17rem\] { left: 17rem; } -.left-\[1px\]{ +.left-\[1px\] { left: 1px; } -.left-\[40\%\]{ +.left-\[40\%\] { left: 40%; } -.left-\[920px\]{ +.left-\[920px\] { left: 920px; } -.right-0{ +.right-0 { right: 0px; } -.right-1{ +.right-1 { right: 0.25rem; } -.right-10{ +.right-10 { right: 2.5rem; } -.right-2{ +.right-2 { right: 0.5rem; } -.right-3{ +.right-3 { right: 0.75rem; } -.right-4{ +.right-4 { right: 1rem; } -.right-5{ +.right-5 { right: 1.25rem; } -.right-7{ +.right-7 { right: 1.75rem; } -.right-8{ +.right-8 { right: 2rem; } -.right-\[1px\]{ +.right-\[1px\] { right: 1px; } -.right-\[20px\]{ +.right-\[20px\] { right: 20px; } -.right-\[8px\]{ +.right-\[8px\] { right: 8px; } -.start-0{ +.start-0 { inset-inline-start: 0px; } -.top-0{ +.top-0 { top: 0px; } -.top-10{ +.top-10 { top: 2.5rem; } -.top-12{ +.top-12 { top: 3rem; } -.top-14{ +.top-14 { top: 3.5rem; } -.top-16{ +.top-16 { top: 4rem; } -.top-20{ +.top-20 { top: 5rem; } -.top-8{ +.top-8 { top: 2rem; } -.top-9{ +.top-9 { top: 2.25rem; } -.top-\[-18px\]{ +.top-\[-18px\] { top: -18px; } -.top-\[1px\]{ +.top-\[1px\] { top: 1px; } -.top-\[33\%\]{ +.top-\[33\%\] { top: 33%; } -.top-\[42\%\]{ +.top-\[42\%\] { top: 42%; } -.top-\[56px\]{ +.top-\[56px\] { top: 56px; } -.top-\[7rem\]{ +.top-\[7rem\] { top: 7rem; } -.z-0{ +.z-0 { z-index: 0; } -.z-10{ +.z-10 { z-index: 10; } -.z-20{ +.z-20 { z-index: 20; } -.z-30{ +.z-30 { z-index: 30; } -.z-40{ +.z-40 { z-index: 40; } -.z-50{ +.z-50 { z-index: 50; } -.z-\[2\]{ +.z-\[2\] { z-index: 2; } -.col-span-1{ +.col-span-1 { grid-column: span 1 / span 1; } -.col-span-10{ +.col-span-10 { grid-column: span 10 / span 10; } -.col-span-2{ +.col-span-2 { grid-column: span 2 / span 2; } -.col-span-3{ +.col-span-3 { grid-column: span 3 / span 3; } -.col-span-4{ +.col-span-4 { grid-column: span 4 / span 4; } -.col-span-6{ +.col-span-6 { grid-column: span 6 / span 6; } -.col-span-7{ +.col-span-7 { grid-column: span 7 / span 7; } -.col-span-8{ +.col-span-8 { grid-column: span 8 / span 8; } -.col-span-full{ +.col-span-full { grid-column: 1 / -1; } -.col-start-1{ +.col-start-1 { grid-column-start: 1; } -.col-start-10{ +.col-start-10 { grid-column-start: 10; } -.col-start-11{ +.col-start-11 { grid-column-start: 11; } -.col-start-12{ +.col-start-12 { grid-column-start: 12; } -.col-start-13{ +.col-start-13 { grid-column-start: 13; } -.col-start-14{ +.col-start-14 { grid-column-start: 14; } -.col-start-17{ +.col-start-17 { grid-column-start: 17; } -.col-start-18{ +.col-start-18 { grid-column-start: 18; } -.col-start-19{ +.col-start-19 { grid-column-start: 19; } -.col-start-2{ +.col-start-2 { grid-column-start: 2; } -.col-start-20{ +.col-start-20 { grid-column-start: 20; } -.col-start-21{ +.col-start-21 { grid-column-start: 21; } -.col-start-22{ +.col-start-22 { grid-column-start: 22; } -.col-start-23{ +.col-start-23 { grid-column-start: 23; } -.col-start-24{ +.col-start-24 { grid-column-start: 24; } -.col-start-3{ +.col-start-3 { grid-column-start: 3; } -.col-start-4{ +.col-start-4 { grid-column-start: 4; } -.col-start-5{ +.col-start-5 { grid-column-start: 5; } -.col-start-6{ +.col-start-6 { grid-column-start: 6; } -.col-start-7{ +.col-start-7 { grid-column-start: 7; } -.col-start-8{ +.col-start-8 { grid-column-start: 8; } -.col-start-9{ +.col-start-9 { grid-column-start: 9; } -.col-end-10{ +.col-end-10 { grid-column-end: 10; } -.col-end-11{ +.col-end-11 { grid-column-end: 11; } -.col-end-12{ +.col-end-12 { grid-column-end: 12; } -.col-end-13{ +.col-end-13 { grid-column-end: 13; } -.col-end-14{ +.col-end-14 { grid-column-end: 14; } -.col-end-15{ +.col-end-15 { grid-column-end: 15; } -.col-end-16{ +.col-end-16 { grid-column-end: 16; } -.col-end-17{ +.col-end-17 { grid-column-end: 17; } -.col-end-18{ +.col-end-18 { grid-column-end: 18; } -.col-end-19{ +.col-end-19 { grid-column-end: 19; } -.col-end-2{ +.col-end-2 { grid-column-end: 2; } -.col-end-20{ +.col-end-20 { grid-column-end: 20; } -.col-end-21{ +.col-end-21 { grid-column-end: 21; } -.col-end-22{ +.col-end-22 { grid-column-end: 22; } -.col-end-23{ +.col-end-23 { grid-column-end: 23; } -.col-end-24{ +.col-end-24 { grid-column-end: 24; } -.col-end-25{ +.col-end-25 { grid-column-end: 25; } -.col-end-3{ +.col-end-3 { grid-column-end: 3; } -.col-end-4{ +.col-end-4 { grid-column-end: 4; } -.col-end-5{ +.col-end-5 { grid-column-end: 5; } -.col-end-6{ +.col-end-6 { grid-column-end: 6; } -.col-end-7{ +.col-end-7 { grid-column-end: 7; } -.col-end-8{ +.col-end-8 { grid-column-end: 8; } -.col-end-9{ +.col-end-9 { grid-column-end: 9; } -.row-span-1{ +.row-span-1 { grid-row: span 1 / span 1; } -.row-span-10{ +.row-span-10 { grid-row: span 10 / span 10; } -.row-span-2{ +.row-span-2 { grid-row: span 2 / span 2; } -.row-span-3{ +.row-span-3 { grid-row: span 3 / span 3; } -.row-span-4{ +.row-span-4 { grid-row: span 4 / span 4; } -.row-span-5{ +.row-span-5 { grid-row: span 5 / span 5; } -.row-span-6{ +.row-span-6 { grid-row: span 6 / span 6; } -.row-span-8{ +.row-span-8 { grid-row: span 8 / span 8; } -.row-span-full{ +.row-span-full { grid-row: 1 / -1; } -.row-start-1{ +.row-start-1 { grid-row-start: 1; } -.row-start-10{ +.row-start-10 { grid-row-start: 10; } -.row-start-11{ +.row-start-11 { grid-row-start: 11; } -.row-start-12{ +.row-start-12 { grid-row-start: 12; } -.row-start-13{ +.row-start-13 { grid-row-start: 13; } -.row-start-14{ +.row-start-14 { grid-row-start: 14; } -.row-start-2{ +.row-start-2 { grid-row-start: 2; } -.row-start-3{ +.row-start-3 { grid-row-start: 3; } -.row-start-4{ +.row-start-4 { grid-row-start: 4; } -.row-start-5{ +.row-start-5 { grid-row-start: 5; } -.row-start-6{ +.row-start-6 { grid-row-start: 6; } -.row-start-7{ +.row-start-7 { grid-row-start: 7; } -.row-start-8{ +.row-start-8 { grid-row-start: 8; } -.row-start-9{ +.row-start-9 { grid-row-start: 9; } -.row-end-10{ +.row-end-10 { grid-row-end: 10; } -.row-end-11{ +.row-end-11 { grid-row-end: 11; } -.row-end-12{ +.row-end-12 { grid-row-end: 12; } -.row-end-13{ +.row-end-13 { grid-row-end: 13; } -.row-end-14{ +.row-end-14 { grid-row-end: 14; } -.row-end-2{ +.row-end-2 { grid-row-end: 2; } -.row-end-3{ +.row-end-3 { grid-row-end: 3; } -.row-end-4{ +.row-end-4 { grid-row-end: 4; } -.row-end-5{ +.row-end-5 { grid-row-end: 5; } -.row-end-6{ +.row-end-6 { grid-row-end: 6; } -.row-end-7{ +.row-end-7 { grid-row-end: 7; } -.row-end-8{ +.row-end-8 { grid-row-end: 8; } -.row-end-9{ +.row-end-9 { grid-row-end: 9; } -.float-right{ +.float-right { float: right; } -.-m-1{ +.-m-1 { margin: -0.25rem; } -.m-1{ +.m-1 { margin: 0.25rem; } -.m-auto{ +.m-auto { margin: auto; } -.mx-1{ +.mx-1 { margin-left: 0.25rem; margin-right: 0.25rem; } -.mx-2{ +.mx-2 { margin-left: 0.5rem; margin-right: 0.5rem; } -.mx-auto{ +.mx-auto { margin-left: auto; margin-right: auto; } -.my-auto{ +.my-auto { margin-top: auto; margin-bottom: auto; } -.-mb-6{ +.-mb-6 { margin-bottom: -1.5rem; } -.-ml-4{ +.-ml-4 { margin-left: -1rem; } -.mb-1{ +.mb-1 { margin-bottom: 0.25rem; } -.mb-2{ +.mb-2 { margin-bottom: 0.5rem; } -.mb-3{ +.mb-3 { margin-bottom: 0.75rem; } -.mb-\[1px\]{ +.mb-\[1px\] { margin-bottom: 1px; } -.ml-1{ +.ml-1 { margin-left: 0.25rem; } -.ml-2{ +.ml-2 { margin-left: 0.5rem; } -.ml-3{ +.ml-3 { margin-left: 0.75rem; } -.ml-4{ +.ml-4 { margin-left: 1rem; } -.ml-5{ +.ml-5 { margin-left: 1.25rem; } -.ml-\[25px\]{ +.ml-\[25px\] { margin-left: 25px; } -.ml-\[5px\]{ +.ml-\[5px\] { margin-left: 5px; } -.mr-0{ +.mr-0 { margin-right: 0px; } -.mr-1{ +.mr-1 { margin-right: 0.25rem; } -.mr-2{ +.mr-2 { margin-right: 0.5rem; } -.mr-3{ +.mr-3 { margin-right: 0.75rem; } -.mr-4{ +.mr-4 { margin-right: 1rem; } -.mr-5{ +.mr-5 { margin-right: 1.25rem; } -.mr-\[25px\]{ +.mr-\[25px\] { margin-right: 25px; } -.mt-1{ +.mt-1 { margin-top: 0.25rem; } -.mt-10{ +.mt-10 { margin-top: 2.5rem; } -.mt-12{ +.mt-12 { margin-top: 3rem; } -.mt-2{ +.mt-2 { margin-top: 0.5rem; } -.mt-20{ +.mt-20 { margin-top: 5rem; } -.mt-3{ +.mt-3 { margin-top: 0.75rem; } -.mt-4{ +.mt-4 { margin-top: 1rem; } -.mt-5{ +.mt-5 { margin-top: 1.25rem; } -.mt-6{ +.mt-6 { margin-top: 1.5rem; } -.mt-8{ +.mt-8 { margin-top: 2rem; } -.mt-\[9\.5rem\]{ +.mt-\[9\.5rem\] { margin-top: 9.5rem; } -.box-border{ +.box-border { -webkit-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; } -.block{ +.block { display: block; } -.inline-block{ +.inline-block { display: inline-block; } -.inline{ +.inline { display: inline; } -.flex{ +.flex { display: -webkit-box; display: -ms-flexbox; display: flex; } -.inline-flex{ +.inline-flex { display: -webkit-inline-box; display: -ms-inline-flexbox; display: inline-flex; } -.table{ +.table { display: table; } -.table-row{ +.table-row { display: table-row; } -.grid{ +.grid { display: grid; } -.contents{ +.contents { display: contents; } -.hidden{ +.hidden { display: none; } -.h-1\/2{ +.h-1\/2 { height: 50%; } -.h-1\/3{ +.h-1\/3 { height: 33.333333%; } -.h-10{ +.h-10 { height: 2.5rem; } -.h-12{ +.h-12 { height: 3rem; } -.h-14{ +.h-14 { height: 3.5rem; } -.h-16{ +.h-16 { height: 4rem; } -.h-2{ +.h-2 { height: 0.5rem; } -.h-2\/3{ +.h-2\/3 { height: 66.666667%; } -.h-20{ +.h-20 { height: 5rem; } -.h-24{ +.h-24 { height: 6rem; } -.h-28{ +.h-28 { height: 7rem; } -.h-3{ +.h-3 { height: 0.75rem; } -.h-3\/4{ +.h-3\/4 { height: 75%; } -.h-32{ +.h-32 { height: 8rem; } -.h-4{ +.h-4 { height: 1rem; } -.h-4\/5{ +.h-4\/5 { height: 80%; } -.h-5{ +.h-5 { height: 1.25rem; } -.h-5\/6{ +.h-5\/6 { height: 83.333333%; } -.h-6{ +.h-6 { height: 1.5rem; } -.h-64{ +.h-64 { height: 16rem; } -.h-7{ +.h-7 { height: 1.75rem; } -.h-8{ +.h-8 { height: 2rem; } -.h-9{ +.h-9 { height: 2.25rem; } -.h-\[100px\]{ +.h-\[100px\] { height: 100px; } -.h-\[110px\]{ +.h-\[110px\] { height: 110px; } -.h-\[120px\]{ +.h-\[120px\] { height: 120px; } -.h-\[150px\]{ +.h-\[150px\] { height: 150px; } -.h-\[15px\]{ +.h-\[15px\] { height: 15px; } -.h-\[16px\]{ +.h-\[16px\] { height: 16px; } -.h-\[170px\]{ +.h-\[170px\] { height: 170px; } -.h-\[18px\]{ +.h-\[18px\] { height: 18px; } -.h-\[200px\]{ +.h-\[200px\] { height: 200px; } -.h-\[20px\]{ +.h-\[20px\] { height: 20px; } -.h-\[210px\]{ +.h-\[210px\] { height: 210px; } -.h-\[250px\]{ +.h-\[250px\] { height: 250px; } -.h-\[25px\]{ +.h-\[25px\] { height: 25px; } -.h-\[27px\]{ +.h-\[27px\] { height: 27px; } -.h-\[280px\]{ +.h-\[280px\] { height: 280px; } -.h-\[28px\]{ +.h-\[28px\] { height: 28px; } -.h-\[30px\]{ +.h-\[30px\] { height: 30px; } -.h-\[32px\]{ +.h-\[32px\] { height: 32px; } -.h-\[34px\]{ +.h-\[34px\] { height: 34px; } -.h-\[36px\]{ +.h-\[36px\] { height: 36px; } -.h-\[38px\]{ +.h-\[38px\] { height: 38px; } -.h-\[40px\]{ +.h-\[40px\] { height: 40px; } -.h-\[430px\]{ +.h-\[430px\] { height: 430px; } -.h-\[48px\]{ +.h-\[48px\] { height: 48px; } -.h-\[492px\]{ +.h-\[492px\] { height: 492px; } -.h-\[50px\]{ +.h-\[50px\] { height: 50px; } -.h-\[554px\]{ +.h-\[554px\] { height: 554px; } -.h-\[55px\]{ +.h-\[55px\] { height: 55px; } -.h-\[60px\]{ +.h-\[60px\] { height: 60px; } -.h-\[65px\]{ +.h-\[65px\] { height: 65px; } -.h-\[70\%\]{ +.h-\[70\%\] { height: 70%; } -.h-\[70px\]{ +.h-\[70px\] { height: 70px; } -.h-\[8\%\]{ +.h-\[8\%\] { height: 8%; } -.h-\[80px\]{ +.h-\[80px\] { height: 80px; } -.h-\[90px\]{ +.h-\[90px\] { height: 90px; } -.h-\[95\%\]{ +.h-\[95\%\] { height: 95%; } -.h-\[95\.5\%\]{ +.h-\[95\.5\%\] { height: 95.5%; } -.h-fit{ +.h-fit { height: -webkit-fit-content; height: -moz-fit-content; height: fit-content; } -.h-full{ +.h-full { height: 100%; } -.h-screen{ +.h-screen { height: 100vh; } -.max-h-10{ +.max-h-10 { max-height: 2.5rem; } -.max-h-12{ +.max-h-12 { max-height: 3rem; } -.max-h-28{ +.max-h-28 { max-height: 7rem; } -.max-h-32{ +.max-h-32 { max-height: 8rem; } -.max-h-36{ +.max-h-36 { max-height: 9rem; } -.max-h-6{ +.max-h-6 { max-height: 1.5rem; } -.max-h-60{ +.max-h-60 { max-height: 15rem; } -.max-h-8{ +.max-h-8 { max-height: 2rem; } -.max-h-9{ +.max-h-9 { max-height: 2.25rem; } -.max-h-\[100px\]{ +.max-h-\[100px\] { max-height: 100px; } -.max-h-\[110px\]{ +.max-h-\[110px\] { max-height: 110px; } -.max-h-\[120px\]{ +.max-h-\[120px\] { max-height: 120px; } -.max-h-\[144px\]{ +.max-h-\[144px\] { max-height: 144px; } -.max-h-\[150px\]{ +.max-h-\[150px\] { max-height: 150px; } -.max-h-\[160px\]{ +.max-h-\[160px\] { max-height: 160px; } -.max-h-\[165px\]{ +.max-h-\[165px\] { max-height: 165px; } -.max-h-\[170px\]{ +.max-h-\[170px\] { max-height: 170px; } -.max-h-\[185px\]{ +.max-h-\[185px\] { max-height: 185px; } -.max-h-\[200px\]{ +.max-h-\[200px\] { max-height: 200px; } -.max-h-\[210px\]{ +.max-h-\[210px\] { max-height: 210px; } -.max-h-\[28px\]{ +.max-h-\[28px\] { max-height: 28px; } -.max-h-\[300px\]{ +.max-h-\[300px\] { max-height: 300px; } -.max-h-\[319px\]{ +.max-h-\[319px\] { max-height: 319px; } -.max-h-\[320px\]{ +.max-h-\[320px\] { max-height: 320px; } -.max-h-\[32px\]{ +.max-h-\[32px\] { max-height: 32px; } -.max-h-\[35px\]{ +.max-h-\[35px\] { max-height: 35px; } -.max-h-\[40px\]{ +.max-h-\[40px\] { max-height: 40px; } -.max-h-\[420px\]{ +.max-h-\[420px\] { max-height: 420px; } -.max-h-\[423px\]{ +.max-h-\[423px\] { max-height: 423px; } -.max-h-\[428px\]{ +.max-h-\[428px\] { max-height: 428px; } -.max-h-\[430px\]{ +.max-h-\[430px\] { max-height: 430px; } -.max-h-\[450px\]{ +.max-h-\[450px\] { max-height: 450px; } -.max-h-\[491px\]{ +.max-h-\[491px\] { max-height: 491px; } -.max-h-\[492px\]{ +.max-h-\[492px\] { max-height: 492px; } -.max-h-\[503px\]{ +.max-h-\[503px\] { max-height: 503px; } -.max-h-\[60px\]{ +.max-h-\[60px\] { max-height: 60px; } -.max-h-\[78px\]{ +.max-h-\[78px\] { max-height: 78px; } -.max-h-full{ +.max-h-full { max-height: 100%; } -.min-h-11{ +.min-h-11 { min-height: 2.75rem; } -.min-h-20{ +.min-h-20 { min-height: 5rem; } -.min-h-7{ +.min-h-7 { min-height: 1.75rem; } -.min-h-9{ +.min-h-9 { min-height: 2.25rem; } -.min-h-\[100px\]{ +.min-h-\[100px\] { min-height: 100px; } -.min-h-\[146px\]{ +.min-h-\[146px\] { min-height: 146px; } -.min-h-\[18px\]{ +.min-h-\[18px\] { min-height: 18px; } -.min-h-\[30px\]{ +.min-h-\[30px\] { min-height: 30px; } -.min-h-\[400px\]{ +.min-h-\[400px\] { min-height: 400px; } -.min-h-\[40px\]{ +.min-h-\[40px\] { min-height: 40px; } -.min-h-\[450px\]{ +.min-h-\[450px\] { min-height: 450px; } -.min-h-\[55px\]{ +.min-h-\[55px\] { min-height: 55px; } -.w-1\/2{ +.w-1\/2 { width: 50%; } -.w-1\/3{ +.w-1\/3 { width: 33.333333%; } -.w-1\/4{ +.w-1\/4 { width: 25%; } -.w-1\/6{ +.w-1\/6 { width: 16.666667%; } -.w-10{ +.w-10 { width: 2.5rem; } -.w-10\/12{ +.w-10\/12 { width: 83.333333%; } -.w-11\/12{ +.w-11\/12 { width: 91.666667%; } -.w-12{ +.w-12 { width: 3rem; } -.w-14{ +.w-14 { width: 3.5rem; } -.w-16{ +.w-16 { width: 4rem; } -.w-2{ +.w-2 { width: 0.5rem; } -.w-2\/3{ +.w-2\/3 { width: 66.666667%; } -.w-20{ +.w-20 { width: 5rem; } -.w-24{ +.w-24 { width: 6rem; } -.w-28{ +.w-28 { width: 7rem; } -.w-3{ +.w-3 { width: 0.75rem; } -.w-3\/4{ +.w-3\/4 { width: 75%; } -.w-3\/5{ +.w-3\/5 { width: 60%; } -.w-32{ +.w-32 { width: 8rem; } -.w-36{ +.w-36 { width: 9rem; } -.w-4{ +.w-4 { width: 1rem; } -.w-4\/5{ +.w-4\/5 { width: 80%; } -.w-4\/6{ +.w-4\/6 { width: 66.666667%; } -.w-40{ +.w-40 { width: 10rem; } -.w-44{ +.w-44 { width: 11rem; } -.w-48{ +.w-48 { width: 12rem; } -.w-5{ +.w-5 { width: 1.25rem; } -.w-5\/6{ +.w-5\/6 { width: 83.333333%; } -.w-52{ +.w-52 { width: 13rem; } -.w-56{ +.w-56 { width: 14rem; } -.w-6{ +.w-6 { width: 1.5rem; } -.w-60{ +.w-60 { width: 15rem; } -.w-7{ +.w-7 { width: 1.75rem; } -.w-72{ +.w-72 { width: 18rem; } -.w-8{ +.w-8 { width: 2rem; } -.w-9{ +.w-9 { width: 2.25rem; } -.w-9\/12{ +.w-9\/12 { width: 75%; } -.w-\[100px\]{ +.w-\[100px\] { width: 100px; } -.w-\[110px\]{ +.w-\[110px\] { width: 110px; } -.w-\[120px\]{ +.w-\[120px\] { width: 120px; } -.w-\[130px\]{ +.w-\[130px\] { width: 130px; } -.w-\[150px\]{ +.w-\[150px\] { width: 150px; } -.w-\[153px\]{ +.w-\[153px\] { width: 153px; } -.w-\[154px\]{ +.w-\[154px\] { width: 154px; } -.w-\[155px\]{ +.w-\[155px\] { width: 155px; } -.w-\[15px\]{ +.w-\[15px\] { width: 15px; } -.w-\[178px\]{ +.w-\[178px\] { width: 178px; } -.w-\[180px\]{ +.w-\[180px\] { width: 180px; } -.w-\[190px\]{ +.w-\[190px\] { width: 190px; } -.w-\[200px\]{ +.w-\[200px\] { width: 200px; } -.w-\[27px\]{ +.w-\[27px\] { width: 27px; } -.w-\[30\%\]{ +.w-\[30\%\] { width: 30%; } -.w-\[32\%\]{ +.w-\[32\%\] { width: 32%; } -.w-\[32px\]{ +.w-\[32px\] { width: 32px; } -.w-\[38px\]{ +.w-\[38px\] { width: 38px; } -.w-\[390px\]{ +.w-\[390px\] { width: 390px; } -.w-\[400px\]{ +.w-\[400px\] { width: 400px; } -.w-\[48px\]{ +.w-\[48px\] { width: 48px; } -.w-\[49\%\]{ +.w-\[49\%\] { width: 49%; } -.w-\[50px\]{ +.w-\[50px\] { width: 50px; } -.w-\[53px\]{ +.w-\[53px\] { width: 53px; } -.w-\[55px\]{ +.w-\[55px\] { width: 55px; } -.w-\[68\%\]{ +.w-\[68\%\] { width: 68%; } -.w-\[70px\]{ +.w-\[70px\] { width: 70px; } -.w-\[74px\]{ +.w-\[74px\] { width: 74px; } -.w-\[80\%\]{ +.w-\[80\%\] { width: 80%; } -.w-\[8rem\]{ +.w-\[8rem\] { width: 8rem; } -.w-fit{ +.w-fit { width: -webkit-fit-content; width: -moz-fit-content; width: fit-content; } -.w-full{ +.w-full { width: 100%; } -.w-max{ +.w-max { width: -webkit-max-content; width: -moz-max-content; width: max-content; } -.w-screen{ +.w-screen { width: 100vw; } -.min-w-\[100px\]{ +.min-w-\[100px\] { min-width: 100px; } -.min-w-\[120px\]{ +.min-w-\[120px\] { min-width: 120px; } -.min-w-\[170px\]{ +.min-w-\[170px\] { min-width: 170px; } -.max-w-10{ +.max-w-10 { max-width: 2.5rem; } -.max-w-\[180px\]{ +.max-w-\[180px\] { max-width: 180px; } -.max-w-full{ +.max-w-full { max-width: 100%; } -.max-w-lg{ +.max-w-lg { max-width: 32rem; } -.max-w-xs{ +.max-w-xs { max-width: 20rem; } -.flex-auto{ +.flex-auto { -webkit-box-flex: 1; - -ms-flex: 1 1 auto; - flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; } -.flex-none{ +.flex-none { -webkit-box-flex: 0; - -ms-flex: none; - flex: none; + -ms-flex: none; + flex: none; } -.flex-shrink{ +.flex-shrink { -ms-flex-negative: 1; - flex-shrink: 1; + flex-shrink: 1; } -.flex-shrink-0{ +.flex-shrink-0 { -ms-flex-negative: 0; - flex-shrink: 0; + flex-shrink: 0; } -.origin-top-right{ +.origin-top-right { -webkit-transform-origin: top right; - transform-origin: top right; + transform-origin: top right; } -.-translate-x-1\/2{ +.-translate-x-1\/2 { --tw-translate-x: -50%; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.-translate-y-1\/2{ +.-translate-y-1\/2 { --tw-translate-y: -50%; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.translate-x-8{ +.translate-x-8 { --tw-translate-x: 2rem; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.translate-y-0{ +.translate-y-0 { --tw-translate-y: 0px; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.-rotate-90{ +.-rotate-90 { --tw-rotate: -90deg; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.rotate-0{ +.rotate-0 { --tw-rotate: 0deg; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.rotate-180{ +.rotate-180 { --tw-rotate: 180deg; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.rotate-45{ +.rotate-45 { --tw-rotate: 45deg; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-100{ +.scale-100 { --tw-scale-x: 1; --tw-scale-y: 1; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-110{ +.scale-110 { --tw-scale-x: 1.1; --tw-scale-y: 1.1; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-125{ +.scale-125 { --tw-scale-x: 1.25; --tw-scale-y: 1.25; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-90{ - --tw-scale-x: .9; - --tw-scale-y: .9; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.scale-90 { + --tw-scale-x: 0.9; + --tw-scale-y: 0.9; + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-95{ - --tw-scale-x: .95; - --tw-scale-y: .95; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.scale-95 { + --tw-scale-x: 0.95; + --tw-scale-y: 0.95; + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-y-0{ +.scale-y-0 { --tw-scale-y: 0; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.scale-y-100{ +.scale-y-100 { --tw-scale-y: 1; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.transform{ - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.transform { + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -@-webkit-keyframes pulse{ - 50%{ - opacity: .5; +@-webkit-keyframes pulse { + 50% { + opacity: 0.5; } } -@keyframes pulse{ - 50%{ - opacity: .5; +@keyframes pulse { + 50% { + opacity: 0.5; } } -.animate-pulse{ +.animate-pulse { -webkit-animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; - animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } -@-webkit-keyframes spin{ - to{ +@-webkit-keyframes spin { + to { -webkit-transform: rotate(360deg); - transform: rotate(360deg); + transform: rotate(360deg); } } -@keyframes spin{ - to{ +@keyframes spin { + to { -webkit-transform: rotate(360deg); - transform: rotate(360deg); + transform: rotate(360deg); } } -.animate-spin{ +.animate-spin { -webkit-animation: spin 1s linear infinite; - animation: spin 1s linear infinite; + animation: spin 1s linear infinite; } -.cursor-default{ +.cursor-default { cursor: default; } -.cursor-not-allowed{ +.cursor-not-allowed { cursor: not-allowed; } -.cursor-pointer{ +.cursor-pointer { cursor: pointer; } -.select-none{ +.select-none { -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } -.resize{ +.resize { resize: both; } -.snap-y{ +.snap-y { -ms-scroll-snap-type: y var(--tw-scroll-snap-strictness); - scroll-snap-type: y var(--tw-scroll-snap-strictness); + scroll-snap-type: y var(--tw-scroll-snap-strictness); } -.snap-mandatory{ +.snap-mandatory { --tw-scroll-snap-strictness: mandatory; } -.appearance-none{ +.appearance-none { -webkit-appearance: none; - -moz-appearance: none; - appearance: none; + -moz-appearance: none; + appearance: none; } -.grid-flow-row{ +.grid-flow-row { grid-auto-flow: row; } -.auto-rows-fr{ +.auto-rows-fr { grid-auto-rows: minmax(0, 1fr); } -.auto-rows-max{ +.auto-rows-max { grid-auto-rows: -webkit-max-content; grid-auto-rows: max-content; } -.auto-rows-min{ +.auto-rows-min { grid-auto-rows: -webkit-min-content; grid-auto-rows: min-content; } -.grid-cols-1{ +.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } -.grid-cols-10{ +.grid-cols-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); } -.grid-cols-11{ +.grid-cols-11 { grid-template-columns: repeat(11, minmax(0, 1fr)); } -.grid-cols-12{ +.grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } -.grid-cols-2{ +.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } -.grid-cols-24{ - grid-template-columns: repeat(24 , minmax(0,1fr)); +.grid-cols-24 { + grid-template-columns: repeat(24, minmax(0, 1fr)); } -.grid-cols-3{ +.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } -.grid-cols-4{ +.grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } -.grid-cols-5{ +.grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } -.grid-cols-6{ +.grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } -.grid-cols-7{ +.grid-cols-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); } -.grid-cols-8{ +.grid-cols-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); } -.grid-cols-9{ +.grid-cols-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); } -.grid-rows-1{ +.grid-rows-1 { grid-template-rows: repeat(1, minmax(0, 1fr)); } -.grid-rows-10{ +.grid-rows-10 { grid-template-rows: repeat(10, minmax(0, 1fr)); } -.grid-rows-11{ +.grid-rows-11 { grid-template-rows: repeat(11, minmax(0, 1fr)); } -.grid-rows-12{ - grid-template-rows: repeat(12 , minmax(0,1fr)); +.grid-rows-12 { + grid-template-rows: repeat(12, minmax(0, 1fr)); } -.grid-rows-13{ - grid-template-rows: repeat(13 , minmax(0,1fr)); +.grid-rows-13 { + grid-template-rows: repeat(13, minmax(0, 1fr)); } -.grid-rows-14{ - grid-template-rows: repeat(14 , minmax(0,1fr)); +.grid-rows-14 { + grid-template-rows: repeat(14, minmax(0, 1fr)); } -.grid-rows-15{ - grid-template-rows: repeat(15 , minmax(0,1fr)); +.grid-rows-15 { + grid-template-rows: repeat(15, minmax(0, 1fr)); } -.grid-rows-2{ +.grid-rows-2 { grid-template-rows: repeat(2, minmax(0, 1fr)); } -.grid-rows-3{ +.grid-rows-3 { grid-template-rows: repeat(3, minmax(0, 1fr)); } -.grid-rows-4{ +.grid-rows-4 { grid-template-rows: repeat(4, minmax(0, 1fr)); } -.grid-rows-5{ +.grid-rows-5 { grid-template-rows: repeat(5, minmax(0, 1fr)); } -.grid-rows-6{ +.grid-rows-6 { grid-template-rows: repeat(6, minmax(0, 1fr)); } -.grid-rows-7{ - grid-template-rows: repeat(7 , minmax(0,1fr)); +.grid-rows-7 { + grid-template-rows: repeat(7, minmax(0, 1fr)); } -.grid-rows-8{ - grid-template-rows: repeat(8 , minmax(0,1fr)); +.grid-rows-8 { + grid-template-rows: repeat(8, minmax(0, 1fr)); } -.grid-rows-9{ +.grid-rows-9 { grid-template-rows: repeat(9, minmax(0, 1fr)); } -.flex-col{ +.flex-col { -webkit-box-orient: vertical; -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } -.flex-wrap{ +.flex-wrap { -ms-flex-wrap: wrap; - flex-wrap: wrap; + flex-wrap: wrap; } -.place-content-center{ +.place-content-center { place-content: center; } -.items-start{ +.items-start { -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; + -ms-flex-align: start; + align-items: flex-start; } -.items-end{ +.items-end { -webkit-box-align: end; - -ms-flex-align: end; - align-items: flex-end; + -ms-flex-align: end; + align-items: flex-end; } -.items-center{ +.items-center { -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; + -ms-flex-align: center; + align-items: center; } -.justify-normal{ +.justify-normal { -webkit-box-pack: normal; - -ms-flex-pack: normal; - justify-content: normal; + -ms-flex-pack: normal; + justify-content: normal; } -.justify-start{ +.justify-start { -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; } -.justify-end{ +.justify-end { -webkit-box-pack: end; - -ms-flex-pack: end; - justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; } -.justify-center{ +.justify-center { -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; + -ms-flex-pack: center; + justify-content: center; } -.justify-between{ +.justify-between { -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; } -.justify-evenly{ +.justify-evenly { -webkit-box-pack: space-evenly; - -ms-flex-pack: space-evenly; - justify-content: space-evenly; + -ms-flex-pack: space-evenly; + justify-content: space-evenly; } -.gap-1{ +.gap-1 { gap: 0.25rem; } -.gap-2{ +.gap-2 { gap: 0.5rem; } -.gap-4{ +.gap-4 { gap: 1rem; } -.gap-5{ +.gap-5 { gap: 1.25rem; } -.gap-x-1{ +.gap-x-1 { -webkit-column-gap: 0.25rem; - -moz-column-gap: 0.25rem; - column-gap: 0.25rem; + -moz-column-gap: 0.25rem; + column-gap: 0.25rem; } -.gap-x-2{ +.gap-x-2 { -webkit-column-gap: 0.5rem; - -moz-column-gap: 0.5rem; - column-gap: 0.5rem; + -moz-column-gap: 0.5rem; + column-gap: 0.5rem; } -.gap-x-8{ +.gap-x-8 { -webkit-column-gap: 2rem; - -moz-column-gap: 2rem; - column-gap: 2rem; + -moz-column-gap: 2rem; + column-gap: 2rem; } -.gap-y-1{ +.gap-y-1 { row-gap: 0.25rem; } -.gap-y-2{ +.gap-y-2 { row-gap: 0.5rem; } -.gap-y-4{ +.gap-y-4 { row-gap: 1rem; } -.gap-y-5{ +.gap-y-5 { row-gap: 1.25rem; } -.space-x-1 > :not([hidden]) ~ :not([hidden]){ +.space-x-1 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.25rem * var(--tw-space-x-reverse)); margin-left: calc(0.25rem * calc(1 - var(--tw-space-x-reverse))); } -.space-x-2 > :not([hidden]) ~ :not([hidden]){ +.space-x-2 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.5rem * var(--tw-space-x-reverse)); margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); } -.space-x-4 > :not([hidden]) ~ :not([hidden]){ +.space-x-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1rem * var(--tw-space-x-reverse)); margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); } -.space-x-6 > :not([hidden]) ~ :not([hidden]){ +.space-x-6 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1.5rem * var(--tw-space-x-reverse)); margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); } -.space-y-1 > :not([hidden]) ~ :not([hidden]){ +.space-y-1 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); } -.space-y-2 > :not([hidden]) ~ :not([hidden]){ +.space-y-2 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); } -.space-y-3 > :not([hidden]) ~ :not([hidden]){ +.space-y-3 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); } -.space-y-4 > :not([hidden]) ~ :not([hidden]){ +.space-y-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } -.space-y-6 > :not([hidden]) ~ :not([hidden]){ +.space-y-6 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); } -.space-y-8 > :not([hidden]) ~ :not([hidden]){ +.space-y-8 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(2rem * var(--tw-space-y-reverse)); } -.space-y-\[1px\] > :not([hidden]) ~ :not([hidden]){ +.space-y-\[1px\] > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(1px * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(1px * var(--tw-space-y-reverse)); } -.divide-x > :not([hidden]) ~ :not([hidden]){ +.divide-x > :not([hidden]) ~ :not([hidden]) { --tw-divide-x-reverse: 0; border-right-width: calc(1px * var(--tw-divide-x-reverse)); border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); } -.divide-y > :not([hidden]) ~ :not([hidden]){ +.divide-y > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } -.divide-y-2 > :not([hidden]) ~ :not([hidden]){ +.divide-y-2 > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(2px * calc(1 - var(--tw-divide-y-reverse))); border-bottom-width: calc(2px * var(--tw-divide-y-reverse)); } -.divide-y-\[1px\] > :not([hidden]) ~ :not([hidden]){ +.divide-y-\[1px\] > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } -.divide-gray-300 > :not([hidden]) ~ :not([hidden]){ +.divide-gray-300 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(209 213 219 / var(--tw-divide-opacity)); } -.divide-gray-400 > :not([hidden]) ~ :not([hidden]){ +.divide-gray-400 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(156 163 175 / var(--tw-divide-opacity)); } -.divide-gray-600 > :not([hidden]) ~ :not([hidden]){ +.divide-gray-600 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(75 85 99 / var(--tw-divide-opacity)); } -.divide-gray-700 > :not([hidden]) ~ :not([hidden]){ +.divide-gray-700 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(55 65 81 / var(--tw-divide-opacity)); } -.self-start{ +.self-start { -ms-flex-item-align: start; - align-self: flex-start; + align-self: flex-start; } -.self-end{ +.self-end { -ms-flex-item-align: end; - align-self: flex-end; + align-self: flex-end; } -.self-center{ +.self-center { -ms-flex-item-align: center; - align-self: center; + align-self: center; } -.justify-self-start{ +.justify-self-start { justify-self: start; } -.justify-self-end{ +.justify-self-end { justify-self: end; } -.justify-self-center{ +.justify-self-center { justify-self: center; } -.overflow-auto{ +.overflow-auto { overflow: auto; } -.overflow-hidden{ +.overflow-hidden { overflow: hidden; } -.overflow-y-auto{ +.overflow-y-auto { overflow-y: auto; } -.overflow-x-hidden{ +.overflow-x-hidden { overflow-x: hidden; } -.overflow-y-hidden{ +.overflow-y-hidden { overflow-y: hidden; } -.overflow-x-scroll{ +.overflow-x-scroll { overflow-x: scroll; } -.overflow-y-scroll{ +.overflow-y-scroll { overflow-y: scroll; } -.overscroll-y-auto{ +.overscroll-y-auto { overscroll-behavior-y: auto; } -.truncate{ +.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.whitespace-nowrap{ +.whitespace-nowrap { white-space: nowrap; } -.whitespace-pre{ +.whitespace-pre { white-space: pre; } -.whitespace-pre-wrap{ +.whitespace-pre-wrap { white-space: pre-wrap; } -.text-wrap{ +.text-wrap { text-wrap: wrap; } -.text-nowrap{ +.text-nowrap { text-wrap: nowrap; } -.break-words{ +.break-words { overflow-wrap: break-word; } -.break-all{ +.break-all { word-break: break-all; } -.rounded{ +.rounded { border-radius: 0.25rem; } -.rounded-2xl{ +.rounded-2xl { border-radius: 1rem; } -.rounded-3xl{ +.rounded-3xl { border-radius: 1.5rem; } -.rounded-\[35px\]{ +.rounded-\[35px\] { border-radius: 35px; } -.rounded-\[4px\]{ +.rounded-\[4px\] { border-radius: 4px; } -.rounded-\[55px\]{ +.rounded-\[55px\] { border-radius: 55px; } -.rounded-\[5px\]{ +.rounded-\[5px\] { border-radius: 5px; } -.rounded-\[75px\]{ +.rounded-\[75px\] { border-radius: 75px; } -.rounded-full{ +.rounded-full { border-radius: 9999px; } -.rounded-lg{ +.rounded-lg { border-radius: 0.5rem; } -.rounded-md{ +.rounded-md { border-radius: 0.375rem; } -.rounded-sm{ +.rounded-sm { border-radius: 0.125rem; } -.rounded-xl{ +.rounded-xl { border-radius: 0.75rem; } -.rounded-b-lg{ +.rounded-b-lg { border-bottom-right-radius: 0.5rem; border-bottom-left-radius: 0.5rem; } -.rounded-b-md{ +.rounded-b-md { border-bottom-right-radius: 0.375rem; border-bottom-left-radius: 0.375rem; } -.rounded-b-sm{ +.rounded-b-sm { border-bottom-right-radius: 0.125rem; border-bottom-left-radius: 0.125rem; } -.rounded-l-md{ +.rounded-l-md { border-top-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem; } -.rounded-l-none{ +.rounded-l-none { border-top-left-radius: 0px; border-bottom-left-radius: 0px; } -.rounded-l-xl{ +.rounded-l-xl { border-top-left-radius: 0.75rem; border-bottom-left-radius: 0.75rem; } -.rounded-r-full{ +.rounded-r-full { border-top-right-radius: 9999px; border-bottom-right-radius: 9999px; } -.rounded-r-md{ +.rounded-r-md { border-top-right-radius: 0.375rem; border-bottom-right-radius: 0.375rem; } -.rounded-r-sm{ +.rounded-r-sm { border-top-right-radius: 0.125rem; border-bottom-right-radius: 0.125rem; } -.rounded-t-\[0\.28rem\]{ +.rounded-t-\[0\.28rem\] { border-top-left-radius: 0.28rem; border-top-right-radius: 0.28rem; } -.rounded-t-\[5px\]{ +.rounded-t-\[5px\] { border-top-left-radius: 5px; border-top-right-radius: 5px; } -.rounded-t-lg{ +.rounded-t-lg { border-top-left-radius: 0.5rem; border-top-right-radius: 0.5rem; } -.rounded-t-md{ +.rounded-t-md { border-top-left-radius: 0.375rem; border-top-right-radius: 0.375rem; } -.rounded-bl-\[37px\]{ +.rounded-bl-\[37px\] { border-bottom-left-radius: 37px; } -.rounded-br-\[40px\]{ +.rounded-br-\[40px\] { border-bottom-right-radius: 40px; } -.rounded-tl-lg{ +.rounded-tl-lg { border-top-left-radius: 0.5rem; } -.rounded-tr-\[40px\]{ +.rounded-tr-\[40px\] { border-top-right-radius: 40px; } -.border{ +.border { border-width: 1px; } -.border-0{ +.border-0 { border-width: 0px; } -.border-2{ +.border-2 { border-width: 2px; } -.border-4{ +.border-4 { border-width: 4px; } -.border-y{ +.border-y { border-top-width: 1px; border-bottom-width: 1px; } -.border-b{ +.border-b { border-bottom-width: 1px; } -.border-b-2{ +.border-b-2 { border-bottom-width: 2px; } -.border-l{ +.border-l { border-left-width: 1px; } -.border-r{ +.border-r { border-right-width: 1px; } -.border-r-2{ +.border-r-2 { border-right-width: 2px; } -.border-r-4{ +.border-r-4 { border-right-width: 4px; } -.border-s-4{ +.border-s-4 { border-inline-start-width: 4px; } -.border-t{ +.border-t { border-top-width: 1px; } -.border-t-0{ +.border-t-0 { border-top-width: 0px; } -.border-t-2{ +.border-t-2 { border-top-width: 2px; } -.border-t-4{ +.border-t-4 { border-top-width: 4px; } -.border-dashed{ +.border-dashed { border-style: dashed; } -.border-none{ +.border-none { border-style: none; } -.border-\[\#171D22\]{ +.border-\[\#171D22\] { --tw-border-opacity: 1; border-color: rgb(23 29 34 / var(--tw-border-opacity)); } -.border-\[\#1c3634\]{ +.border-\[\#1c3634\] { --tw-border-opacity: 1; border-color: rgb(28 54 52 / var(--tw-border-opacity)); } -.border-\[\#2c3136\]{ +.border-\[\#2c3136\] { --tw-border-opacity: 1; border-color: rgb(44 49 54 / var(--tw-border-opacity)); } -.border-\[\#33393E\]{ +.border-\[\#33393E\] { --tw-border-opacity: 1; border-color: rgb(51 57 62 / var(--tw-border-opacity)); } -.border-\[\#336666\]{ +.border-\[\#336666\] { --tw-border-opacity: 1; border-color: rgb(51 102 102 / var(--tw-border-opacity)); } -.border-\[\#3e4347\]{ +.border-\[\#3e4347\] { --tw-border-opacity: 1; border-color: rgb(62 67 71 / var(--tw-border-opacity)); } -.border-\[\#4b8585\]{ +.border-\[\#4b8585\] { --tw-border-opacity: 1; border-color: rgb(75 133 133 / var(--tw-border-opacity)); } -.border-\[\#6c7e78\]{ +.border-\[\#6c7e78\] { --tw-border-opacity: 1; border-color: rgb(108 126 120 / var(--tw-border-opacity)); } -.border-blue-100{ +.border-blue-100 { --tw-border-opacity: 1; border-color: rgb(219 234 254 / var(--tw-border-opacity)); } -.border-blue-300{ +.border-blue-300 { --tw-border-opacity: 1; border-color: rgb(147 197 253 / var(--tw-border-opacity)); } -.border-blue-400{ +.border-blue-400 { --tw-border-opacity: 1; border-color: rgb(96 165 250 / var(--tw-border-opacity)); } -.border-blue-500{ +.border-blue-500 { --tw-border-opacity: 1; border-color: rgb(59 130 246 / var(--tw-border-opacity)); } -.border-gray-100{ +.border-gray-100 { --tw-border-opacity: 1; border-color: rgb(243 244 246 / var(--tw-border-opacity)); } -.border-gray-200{ +.border-gray-200 { --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity)); } -.border-gray-300{ +.border-gray-300 { --tw-border-opacity: 1; border-color: rgb(209 213 219 / var(--tw-border-opacity)); } -.border-gray-400{ +.border-gray-400 { --tw-border-opacity: 1; border-color: rgb(156 163 175 / var(--tw-border-opacity)); } -.border-gray-500{ +.border-gray-500 { --tw-border-opacity: 1; border-color: rgb(107 114 128 / var(--tw-border-opacity)); } -.border-gray-600{ +.border-gray-600 { --tw-border-opacity: 1; border-color: rgb(75 85 99 / var(--tw-border-opacity)); } -.border-gray-700{ +.border-gray-700 { --tw-border-opacity: 1; border-color: rgb(55 65 81 / var(--tw-border-opacity)); } -.border-gray-800{ +.border-gray-800 { --tw-border-opacity: 1; border-color: rgb(31 41 55 / var(--tw-border-opacity)); } -.border-gray-950{ +.border-gray-950 { --tw-border-opacity: 1; border-color: rgb(3 7 18 / var(--tw-border-opacity)); } -.border-green-500{ +.border-green-500 { --tw-border-opacity: 1; border-color: rgb(34 197 94 / var(--tw-border-opacity)); } -.border-orange-500{ +.border-orange-500 { --tw-border-opacity: 1; border-color: rgb(249 115 22 / var(--tw-border-opacity)); } -.border-red-400{ +.border-red-400 { --tw-border-opacity: 1; border-color: rgb(248 113 113 / var(--tw-border-opacity)); } -.border-red-500{ +.border-red-500 { --tw-border-opacity: 1; border-color: rgb(239 68 68 / var(--tw-border-opacity)); } -.border-red-600{ +.border-red-600 { --tw-border-opacity: 1; border-color: rgb(220 38 38 / var(--tw-border-opacity)); } -.border-red-800{ +.border-red-800 { --tw-border-opacity: 1; border-color: rgb(153 27 27 / var(--tw-border-opacity)); } -.border-slate-500{ +.border-slate-500 { --tw-border-opacity: 1; border-color: rgb(100 116 139 / var(--tw-border-opacity)); } -.border-teal-200{ +.border-teal-200 { --tw-border-opacity: 1; border-color: rgb(153 246 228 / var(--tw-border-opacity)); } -.border-teal-300{ +.border-teal-300 { --tw-border-opacity: 1; border-color: rgb(94 234 212 / var(--tw-border-opacity)); } -.border-teal-500{ +.border-teal-500 { --tw-border-opacity: 1; border-color: rgb(20 184 166 / var(--tw-border-opacity)); } -.border-teal-600{ +.border-teal-600 { --tw-border-opacity: 1; border-color: rgb(13 148 136 / var(--tw-border-opacity)); } -.border-teal-700{ +.border-teal-700 { --tw-border-opacity: 1; border-color: rgb(15 118 110 / var(--tw-border-opacity)); } -.border-teal-800{ +.border-teal-800 { --tw-border-opacity: 1; border-color: rgb(17 94 89 / var(--tw-border-opacity)); } -.border-transparent{ +.border-transparent { border-color: transparent; } -.border-white{ +.border-white { --tw-border-opacity: 1; border-color: rgb(255 255 255 / var(--tw-border-opacity)); } -.border-b-transparent{ +.border-b-transparent { border-bottom-color: transparent; } -.border-l-gray-200{ +.border-l-gray-200 { --tw-border-opacity: 1; border-left-color: rgb(229 231 235 / var(--tw-border-opacity)); } -.border-r-\[\#264744\]{ +.border-r-\[\#264744\] { --tw-border-opacity: 1; border-right-color: rgb(38 71 68 / var(--tw-border-opacity)); } -.border-r-\[\#88b79a\]{ +.border-r-\[\#88b79a\] { --tw-border-opacity: 1; border-right-color: rgb(136 183 154 / var(--tw-border-opacity)); } -.border-r-blue-600{ +.border-r-blue-600 { --tw-border-opacity: 1; border-right-color: rgb(37 99 235 / var(--tw-border-opacity)); } -.border-r-transparent{ +.border-r-transparent { border-right-color: transparent; } -.border-r-white{ +.border-r-white { --tw-border-opacity: 1; border-right-color: rgb(255 255 255 / var(--tw-border-opacity)); } -.border-t-\[\#88b79a\]{ +.border-t-\[\#88b79a\] { --tw-border-opacity: 1; border-top-color: rgb(136 183 154 / var(--tw-border-opacity)); } -.border-t-blue-600{ +.border-t-blue-600 { --tw-border-opacity: 1; border-top-color: rgb(37 99 235 / var(--tw-border-opacity)); } -.border-t-white{ +.border-t-white { --tw-border-opacity: 1; border-top-color: rgb(255 255 255 / var(--tw-border-opacity)); } -.bg-\[\#0F1217\]{ +.bg-\[\#0F1217\] { --tw-bg-opacity: 1; background-color: rgb(15 18 23 / var(--tw-bg-opacity)); } -.bg-\[\#0d0d0e\]{ +.bg-\[\#0d0d0e\] { --tw-bg-opacity: 1; background-color: rgb(13 13 14 / var(--tw-bg-opacity)); } -.bg-\[\#111213\]{ +.bg-\[\#111213\] { --tw-bg-opacity: 1; background-color: rgb(17 18 19 / var(--tw-bg-opacity)); } -.bg-\[\#111315\]{ +.bg-\[\#111315\] { --tw-bg-opacity: 1; background-color: rgb(17 19 21 / var(--tw-bg-opacity)); } -.bg-\[\#131313\]{ +.bg-\[\#131313\] { --tw-bg-opacity: 1; background-color: rgb(19 19 19 / var(--tw-bg-opacity)); } -.bg-\[\#141516\]{ +.bg-\[\#141516\] { --tw-bg-opacity: 1; background-color: rgb(20 21 22 / var(--tw-bg-opacity)); } -.bg-\[\#14171a\]{ +.bg-\[\#14171a\] { --tw-bg-opacity: 1; background-color: rgb(20 23 26 / var(--tw-bg-opacity)); } -.bg-\[\#151618\]{ +.bg-\[\#151618\] { --tw-bg-opacity: 1; background-color: rgb(21 22 24 / var(--tw-bg-opacity)); } -.bg-\[\#151a1e\]{ +.bg-\[\#151a1e\] { --tw-bg-opacity: 1; background-color: rgb(21 26 30 / var(--tw-bg-opacity)); } -.bg-\[\#161717\]{ +.bg-\[\#161717\] { --tw-bg-opacity: 1; background-color: rgb(22 23 23 / var(--tw-bg-opacity)); } -.bg-\[\#171D22\]{ +.bg-\[\#171D22\] { --tw-bg-opacity: 1; background-color: rgb(23 29 34 / var(--tw-bg-opacity)); } -.bg-\[\#171a1b\]{ +.bg-\[\#171a1b\] { --tw-bg-opacity: 1; background-color: rgb(23 26 27 / var(--tw-bg-opacity)); } -.bg-\[\#171a1c\]{ +.bg-\[\#171a1c\] { --tw-bg-opacity: 1; background-color: rgb(23 26 28 / var(--tw-bg-opacity)); } -.bg-\[\#17A2B8\]{ +.bg-\[\#17A2B8\] { --tw-bg-opacity: 1; background-color: rgb(23 162 184 / var(--tw-bg-opacity)); } -.bg-\[\#18191a\]{ +.bg-\[\#18191a\] { --tw-bg-opacity: 1; background-color: rgb(24 25 26 / var(--tw-bg-opacity)); } -.bg-\[\#191b1e\]{ +.bg-\[\#191b1e\] { --tw-bg-opacity: 1; background-color: rgb(25 27 30 / var(--tw-bg-opacity)); } -.bg-\[\#191c21\]{ +.bg-\[\#191c21\] { --tw-bg-opacity: 1; background-color: rgb(25 28 33 / var(--tw-bg-opacity)); } -.bg-\[\#1BA5F8\]{ +.bg-\[\#1BA5F8\] { --tw-bg-opacity: 1; background-color: rgb(27 165 248 / var(--tw-bg-opacity)); } -.bg-\[\#1E2429\]{ +.bg-\[\#1E2429\] { --tw-bg-opacity: 1; background-color: rgb(30 36 41 / var(--tw-bg-opacity)); } -.bg-\[\#1a2e2c\]{ +.bg-\[\#1a2e2c\] { --tw-bg-opacity: 1; background-color: rgb(26 46 44 / var(--tw-bg-opacity)); } -.bg-\[\#1b1b1d\]{ +.bg-\[\#1b1b1d\] { --tw-bg-opacity: 1; background-color: rgb(27 27 29 / var(--tw-bg-opacity)); } -.bg-\[\#1b1c1c\]{ +.bg-\[\#1b1c1c\] { --tw-bg-opacity: 1; background-color: rgb(27 28 28 / var(--tw-bg-opacity)); } -.bg-\[\#1b1d1f\]{ +.bg-\[\#1b1d1f\] { --tw-bg-opacity: 1; background-color: rgb(27 29 31 / var(--tw-bg-opacity)); } -.bg-\[\#1b3231\]{ +.bg-\[\#1b3231\] { --tw-bg-opacity: 1; background-color: rgb(27 50 49 / var(--tw-bg-opacity)); } -.bg-\[\#1c1d1d\]{ +.bg-\[\#1c1d1d\] { --tw-bg-opacity: 1; background-color: rgb(28 29 29 / var(--tw-bg-opacity)); } -.bg-\[\#1c2021\]{ +.bg-\[\#1c2021\] { --tw-bg-opacity: 1; background-color: rgb(28 32 33 / var(--tw-bg-opacity)); } -.bg-\[\#1d1d1e\]{ +.bg-\[\#1d1d1e\] { --tw-bg-opacity: 1; background-color: rgb(29 29 30 / var(--tw-bg-opacity)); } -.bg-\[\#1d1e1f\]{ +.bg-\[\#1d1e1f\] { --tw-bg-opacity: 1; background-color: rgb(29 30 31 / var(--tw-bg-opacity)); } -.bg-\[\#1d1f20\]{ +.bg-\[\#1d1f20\] { --tw-bg-opacity: 1; background-color: rgb(29 31 32 / var(--tw-bg-opacity)); } -.bg-\[\#1d1f21\]{ +.bg-\[\#1d1f21\] { --tw-bg-opacity: 1; background-color: rgb(29 31 33 / var(--tw-bg-opacity)); } -.bg-\[\#1f2123\]{ +.bg-\[\#1f2123\] { --tw-bg-opacity: 1; background-color: rgb(31 33 35 / var(--tw-bg-opacity)); } -.bg-\[\#1f2226\]{ +.bg-\[\#1f2226\] { --tw-bg-opacity: 1; background-color: rgb(31 34 38 / var(--tw-bg-opacity)); } -.bg-\[\#202123\]{ +.bg-\[\#202123\] { --tw-bg-opacity: 1; background-color: rgb(32 33 35 / var(--tw-bg-opacity)); } -.bg-\[\#202225\]{ +.bg-\[\#202225\] { --tw-bg-opacity: 1; background-color: rgb(32 34 37 / var(--tw-bg-opacity)); } -.bg-\[\#202632\]{ +.bg-\[\#202632\] { --tw-bg-opacity: 1; background-color: rgb(32 38 50 / var(--tw-bg-opacity)); } -.bg-\[\#212225\]{ +.bg-\[\#212225\] { --tw-bg-opacity: 1; background-color: rgb(33 34 37 / var(--tw-bg-opacity)); } -.bg-\[\#212629\]{ +.bg-\[\#212629\] { --tw-bg-opacity: 1; background-color: rgb(33 38 41 / var(--tw-bg-opacity)); } -.bg-\[\#21272c\]{ +.bg-\[\#21272c\] { --tw-bg-opacity: 1; background-color: rgb(33 39 44 / var(--tw-bg-opacity)); } -.bg-\[\#222526\]{ +.bg-\[\#222526\] { --tw-bg-opacity: 1; background-color: rgb(34 37 38 / var(--tw-bg-opacity)); } -.bg-\[\#224141\]{ +.bg-\[\#224141\] { --tw-bg-opacity: 1; background-color: rgb(34 65 65 / var(--tw-bg-opacity)); } -.bg-\[\#232428\]{ +.bg-\[\#232428\] { --tw-bg-opacity: 1; background-color: rgb(35 36 40 / var(--tw-bg-opacity)); } -.bg-\[\#232528\]{ +.bg-\[\#232528\] { --tw-bg-opacity: 1; background-color: rgb(35 37 40 / var(--tw-bg-opacity)); } -.bg-\[\#242529\]{ +.bg-\[\#242529\] { --tw-bg-opacity: 1; background-color: rgb(36 37 41 / var(--tw-bg-opacity)); } -.bg-\[\#242628\]{ +.bg-\[\#242628\] { --tw-bg-opacity: 1; background-color: rgb(36 38 40 / var(--tw-bg-opacity)); } -.bg-\[\#243535\]{ +.bg-\[\#243535\] { --tw-bg-opacity: 1; background-color: rgb(36 53 53 / var(--tw-bg-opacity)); } -.bg-\[\#243d36\]{ +.bg-\[\#243d36\] { --tw-bg-opacity: 1; background-color: rgb(36 61 54 / var(--tw-bg-opacity)); } -.bg-\[\#252525\]{ +.bg-\[\#252525\] { --tw-bg-opacity: 1; background-color: rgb(37 37 37 / var(--tw-bg-opacity)); } -.bg-\[\#264744\]{ +.bg-\[\#264744\] { --tw-bg-opacity: 1; background-color: rgb(38 71 68 / var(--tw-bg-opacity)); } -.bg-\[\#282a2c\]{ +.bg-\[\#282a2c\] { --tw-bg-opacity: 1; background-color: rgb(40 42 44 / var(--tw-bg-opacity)); } -.bg-\[\#292e32\]{ +.bg-\[\#292e32\] { --tw-bg-opacity: 1; background-color: rgb(41 46 50 / var(--tw-bg-opacity)); } -.bg-\[\#2a2e30\]{ +.bg-\[\#2a2e30\] { --tw-bg-opacity: 1; background-color: rgb(42 46 48 / var(--tw-bg-opacity)); } -.bg-\[\#2c3136\]{ +.bg-\[\#2c3136\] { --tw-bg-opacity: 1; background-color: rgb(44 49 54 / var(--tw-bg-opacity)); } -.bg-\[\#2d3035\]{ +.bg-\[\#2d3035\] { --tw-bg-opacity: 1; background-color: rgb(45 48 53 / var(--tw-bg-opacity)); } -.bg-\[\#2d3438\]{ +.bg-\[\#2d3438\] { --tw-bg-opacity: 1; background-color: rgb(45 52 56 / var(--tw-bg-opacity)); } -.bg-\[\#2e5151\]{ +.bg-\[\#2e5151\] { --tw-bg-opacity: 1; background-color: rgb(46 81 81 / var(--tw-bg-opacity)); } -.bg-\[\#2f373c\]{ +.bg-\[\#2f373c\] { --tw-bg-opacity: 1; background-color: rgb(47 55 60 / var(--tw-bg-opacity)); } -.bg-\[\#2f5a5a\]{ +.bg-\[\#2f5a5a\] { --tw-bg-opacity: 1; background-color: rgb(47 90 90 / var(--tw-bg-opacity)); } -.bg-\[\#303232\]{ +.bg-\[\#303232\] { --tw-bg-opacity: 1; background-color: rgb(48 50 50 / var(--tw-bg-opacity)); } -.bg-\[\#313539\]{ +.bg-\[\#313539\] { --tw-bg-opacity: 1; background-color: rgb(49 53 57 / var(--tw-bg-opacity)); } -.bg-\[\#32363A\]{ +.bg-\[\#32363A\] { --tw-bg-opacity: 1; background-color: rgb(50 54 58 / var(--tw-bg-opacity)); } -.bg-\[\#333539\]{ +.bg-\[\#333539\] { --tw-bg-opacity: 1; background-color: rgb(51 53 57 / var(--tw-bg-opacity)); } -.bg-\[\#33393E\]{ +.bg-\[\#33393E\] { --tw-bg-opacity: 1; background-color: rgb(51 57 62 / var(--tw-bg-opacity)); } -.bg-\[\#33393e\]{ +.bg-\[\#33393e\] { --tw-bg-opacity: 1; background-color: rgb(51 57 62 / var(--tw-bg-opacity)); } -.bg-\[\#334B3F\]{ +.bg-\[\#334B3F\] { --tw-bg-opacity: 1; background-color: rgb(51 75 63 / var(--tw-bg-opacity)); } -.bg-\[\#334d4d\]{ +.bg-\[\#334d4d\] { --tw-bg-opacity: 1; background-color: rgb(51 77 77 / var(--tw-bg-opacity)); } -.bg-\[\#336666\]{ +.bg-\[\#336666\] { --tw-bg-opacity: 1; background-color: rgb(51 102 102 / var(--tw-bg-opacity)); } -.bg-\[\#343434\]{ +.bg-\[\#343434\] { --tw-bg-opacity: 1; background-color: rgb(52 52 52 / var(--tw-bg-opacity)); } -.bg-\[\#387272\]{ +.bg-\[\#387272\] { --tw-bg-opacity: 1; background-color: rgb(56 114 114 / var(--tw-bg-opacity)); } -.bg-\[\#393939\]{ +.bg-\[\#393939\] { --tw-bg-opacity: 1; background-color: rgb(57 57 57 / var(--tw-bg-opacity)); } -.bg-\[\#3d4244\]{ +.bg-\[\#3d4244\] { --tw-bg-opacity: 1; background-color: rgb(61 66 68 / var(--tw-bg-opacity)); } -.bg-\[\#3d4449\]{ +.bg-\[\#3d4449\] { --tw-bg-opacity: 1; background-color: rgb(61 68 73 / var(--tw-bg-opacity)); } -.bg-\[\#3e4347\]{ +.bg-\[\#3e4347\] { --tw-bg-opacity: 1; background-color: rgb(62 67 71 / var(--tw-bg-opacity)); } -.bg-\[\#495056\]{ +.bg-\[\#495056\] { --tw-bg-opacity: 1; background-color: rgb(73 80 86 / var(--tw-bg-opacity)); } -.bg-\[\#4D56CB\]{ +.bg-\[\#4D56CB\] { --tw-bg-opacity: 1; background-color: rgb(77 86 203 / var(--tw-bg-opacity)); } -.bg-\[\#4d7575\]{ +.bg-\[\#4d7575\] { --tw-bg-opacity: 1; background-color: rgb(77 117 117 / var(--tw-bg-opacity)); } -.bg-\[\#503C3C\]{ +.bg-\[\#503C3C\] { --tw-bg-opacity: 1; background-color: rgb(80 60 60 / var(--tw-bg-opacity)); } -.bg-\[\#505f6d\]{ +.bg-\[\#505f6d\] { --tw-bg-opacity: 1; background-color: rgb(80 95 109 / var(--tw-bg-opacity)); } -.bg-\[\#537263\]{ +.bg-\[\#537263\] { --tw-bg-opacity: 1; background-color: rgb(83 114 99 / var(--tw-bg-opacity)); } -.bg-\[\#578f84\]{ +.bg-\[\#578f84\] { --tw-bg-opacity: 1; background-color: rgb(87 143 132 / var(--tw-bg-opacity)); } -.bg-\[\#609879\]{ +.bg-\[\#609879\] { --tw-bg-opacity: 1; background-color: rgb(96 152 121 / var(--tw-bg-opacity)); } -.bg-\[\#A0A0A0\]{ +.bg-\[\#A0A0A0\] { --tw-bg-opacity: 1; background-color: rgb(160 160 160 / var(--tw-bg-opacity)); } -.bg-\[\#D1BB9E\]{ +.bg-\[\#D1BB9E\] { --tw-bg-opacity: 1; background-color: rgb(209 187 158 / var(--tw-bg-opacity)); } -.bg-\[\#F7C566\]{ +.bg-\[\#F7C566\] { --tw-bg-opacity: 1; background-color: rgb(247 197 102 / var(--tw-bg-opacity)); } -.bg-\[\#a7aeb5\]{ +.bg-\[\#a7aeb5\] { --tw-bg-opacity: 1; background-color: rgb(167 174 181 / var(--tw-bg-opacity)); } -.bg-\[\#a846b8\]{ +.bg-\[\#a846b8\] { --tw-bg-opacity: 1; background-color: rgb(168 70 184 / var(--tw-bg-opacity)); } -.bg-\[\#caced1\]{ +.bg-\[\#caced1\] { --tw-bg-opacity: 1; background-color: rgb(202 206 209 / var(--tw-bg-opacity)); } -.bg-\[\#e8ebeb\]{ +.bg-\[\#e8ebeb\] { --tw-bg-opacity: 1; background-color: rgb(232 235 235 / var(--tw-bg-opacity)); } -.bg-\[\#eaecee\]{ +.bg-\[\#eaecee\] { --tw-bg-opacity: 1; background-color: rgb(234 236 238 / var(--tw-bg-opacity)); } -.bg-\[\#fb923c\]{ +.bg-\[\#fb923c\] { --tw-bg-opacity: 1; background-color: rgb(251 146 60 / var(--tw-bg-opacity)); } -.bg-amber-400{ +.bg-amber-400 { --tw-bg-opacity: 1; background-color: rgb(251 191 36 / var(--tw-bg-opacity)); } -.bg-black{ +.bg-black { --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); } -.bg-blue-300{ +.bg-blue-300 { --tw-bg-opacity: 1; background-color: rgb(147 197 253 / var(--tw-bg-opacity)); } -.bg-blue-400{ +.bg-blue-400 { --tw-bg-opacity: 1; background-color: rgb(96 165 250 / var(--tw-bg-opacity)); } -.bg-blue-500{ +.bg-blue-500 { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } -.bg-blue-900{ +.bg-blue-900 { --tw-bg-opacity: 1; background-color: rgb(30 58 138 / var(--tw-bg-opacity)); } -.bg-cyan-300{ +.bg-cyan-300 { --tw-bg-opacity: 1; background-color: rgb(103 232 249 / var(--tw-bg-opacity)); } -.bg-gray-100{ +.bg-gray-100 { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } -.bg-gray-200{ +.bg-gray-200 { --tw-bg-opacity: 1; background-color: rgb(229 231 235 / var(--tw-bg-opacity)); } -.bg-gray-300{ +.bg-gray-300 { --tw-bg-opacity: 1; background-color: rgb(209 213 219 / var(--tw-bg-opacity)); } -.bg-gray-400{ +.bg-gray-400 { --tw-bg-opacity: 1; background-color: rgb(156 163 175 / var(--tw-bg-opacity)); } -.bg-gray-50{ +.bg-gray-50 { --tw-bg-opacity: 1; background-color: rgb(249 250 251 / var(--tw-bg-opacity)); } -.bg-gray-500{ +.bg-gray-500 { --tw-bg-opacity: 1; background-color: rgb(107 114 128 / var(--tw-bg-opacity)); } -.bg-gray-600{ +.bg-gray-600 { --tw-bg-opacity: 1; background-color: rgb(75 85 99 / var(--tw-bg-opacity)); } -.bg-gray-700{ +.bg-gray-700 { --tw-bg-opacity: 1; background-color: rgb(55 65 81 / var(--tw-bg-opacity)); } -.bg-gray-800{ +.bg-gray-800 { --tw-bg-opacity: 1; background-color: rgb(31 41 55 / var(--tw-bg-opacity)); } -.bg-gray-900{ +.bg-gray-900 { --tw-bg-opacity: 1; background-color: rgb(17 24 39 / var(--tw-bg-opacity)); } -.bg-green-400{ +.bg-green-400 { --tw-bg-opacity: 1; background-color: rgb(74 222 128 / var(--tw-bg-opacity)); } -.bg-green-500{ +.bg-green-500 { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } -.bg-green-600{ +.bg-green-600 { --tw-bg-opacity: 1; background-color: rgb(22 163 74 / var(--tw-bg-opacity)); } -.bg-green-700{ +.bg-green-700 { --tw-bg-opacity: 1; background-color: rgb(21 128 61 / var(--tw-bg-opacity)); } -.bg-green-800{ +.bg-green-800 { --tw-bg-opacity: 1; background-color: rgb(22 101 52 / var(--tw-bg-opacity)); } -.bg-lime-900{ +.bg-lime-900 { --tw-bg-opacity: 1; background-color: rgb(54 83 20 / var(--tw-bg-opacity)); } -.bg-orange-500{ +.bg-orange-500 { --tw-bg-opacity: 1; background-color: rgb(249 115 22 / var(--tw-bg-opacity)); } -.bg-red-100{ +.bg-red-100 { --tw-bg-opacity: 1; background-color: rgb(254 226 226 / var(--tw-bg-opacity)); } -.bg-red-300{ +.bg-red-300 { --tw-bg-opacity: 1; background-color: rgb(252 165 165 / var(--tw-bg-opacity)); } -.bg-red-500{ +.bg-red-500 { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } -.bg-red-600{ +.bg-red-600 { --tw-bg-opacity: 1; background-color: rgb(220 38 38 / var(--tw-bg-opacity)); } -.bg-red-700{ +.bg-red-700 { --tw-bg-opacity: 1; background-color: rgb(185 28 28 / var(--tw-bg-opacity)); } -.bg-red-800{ +.bg-red-800 { --tw-bg-opacity: 1; background-color: rgb(153 27 27 / var(--tw-bg-opacity)); } -.bg-slate-200{ +.bg-slate-200 { --tw-bg-opacity: 1; background-color: rgb(226 232 240 / var(--tw-bg-opacity)); } -.bg-slate-400{ +.bg-slate-400 { --tw-bg-opacity: 1; background-color: rgb(148 163 184 / var(--tw-bg-opacity)); } -.bg-slate-600{ +.bg-slate-600 { --tw-bg-opacity: 1; background-color: rgb(71 85 105 / var(--tw-bg-opacity)); } -.bg-teal-500{ +.bg-teal-500 { --tw-bg-opacity: 1; background-color: rgb(20 184 166 / var(--tw-bg-opacity)); } -.bg-teal-600{ +.bg-teal-600 { --tw-bg-opacity: 1; background-color: rgb(13 148 136 / var(--tw-bg-opacity)); } -.bg-teal-700{ +.bg-teal-700 { --tw-bg-opacity: 1; background-color: rgb(15 118 110 / var(--tw-bg-opacity)); } -.bg-teal-800{ +.bg-teal-800 { --tw-bg-opacity: 1; background-color: rgb(17 94 89 / var(--tw-bg-opacity)); } -.bg-transparent{ +.bg-transparent { background-color: transparent; } -.bg-violet-500{ +.bg-violet-500 { --tw-bg-opacity: 1; background-color: rgb(139 92 246 / var(--tw-bg-opacity)); } -.bg-violet-900{ +.bg-violet-900 { --tw-bg-opacity: 1; background-color: rgb(76 29 149 / var(--tw-bg-opacity)); } -.bg-white{ +.bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.bg-yellow-400{ +.bg-yellow-400 { --tw-bg-opacity: 1; background-color: rgb(250 204 21 / var(--tw-bg-opacity)); } -.bg-zinc-700{ +.bg-zinc-700 { --tw-bg-opacity: 1; background-color: rgb(63 63 70 / var(--tw-bg-opacity)); } -.bg-opacity-80{ +.bg-opacity-80 { --tw-bg-opacity: 0.8; } -.bg-gradient-to-b{ +.bg-gradient-to-b { background-image: -webkit-gradient(linear, left top, left bottom, from(var(--tw-gradient-stops))); background-image: linear-gradient(to bottom, var(--tw-gradient-stops)); } -.from-\[\#264744\]{ +.from-\[\#264744\] { --tw-gradient-from: #264744 var(--tw-gradient-from-position); --tw-gradient-to: rgb(38 71 68 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } -.from-10\%{ +.from-10\% { --tw-gradient-from-position: 10%; } -.via-\[\#325d5a\]{ - --tw-gradient-to: rgb(50 93 90 / 0) var(--tw-gradient-to-position); +.via-\[\#325d5a\] { + --tw-gradient-to: rgb(50 93 90 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), #325d5a var(--tw-gradient-via-position), var(--tw-gradient-to); } -.to-\[\#264744\]{ +.to-\[\#264744\] { --tw-gradient-to: #264744 var(--tw-gradient-to-position); } -.to-95\%{ +.to-95\% { --tw-gradient-to-position: 95%; } -.bg-contain{ +.bg-contain { background-size: contain; } -.bg-cover{ +.bg-cover { background-size: cover; } -.bg-fixed{ +.bg-fixed { background-attachment: fixed; } -.bg-center{ +.bg-center { background-position: center; } -.bg-no-repeat{ +.bg-no-repeat { background-repeat: no-repeat; } -.fill-current{ +.fill-current { fill: currentColor; } -.object-cover{ +.object-cover { -o-object-fit: cover; - object-fit: cover; + object-fit: cover; } -.p-1{ +.p-1 { padding: 0.25rem; } -.p-2{ +.p-2 { padding: 0.5rem; } -.p-3{ +.p-3 { padding: 0.75rem; } -.p-4{ +.p-4 { padding: 1rem; } -.p-5{ +.p-5 { padding: 1.25rem; } -.p-8{ +.p-8 { padding: 2rem; } -.p-\[1px\]{ +.p-\[1px\] { padding: 1px; } -.p-\[2px\]{ +.p-\[2px\] { padding: 2px; } -.p-\[3px\]{ +.p-\[3px\] { padding: 3px; } -.p-\[4px\]{ +.p-\[4px\] { padding: 4px; } -.px-1{ +.px-1 { padding-left: 0.25rem; padding-right: 0.25rem; } -.px-2{ +.px-2 { padding-left: 0.5rem; padding-right: 0.5rem; } -.px-20{ +.px-20 { padding-left: 5rem; padding-right: 5rem; } -.px-3{ +.px-3 { padding-left: 0.75rem; padding-right: 0.75rem; } -.px-4{ +.px-4 { padding-left: 1rem; padding-right: 1rem; } -.px-5{ +.px-5 { padding-left: 1.25rem; padding-right: 1.25rem; } -.px-6{ +.px-6 { padding-left: 1.5rem; padding-right: 1.5rem; } -.px-8{ +.px-8 { padding-left: 2rem; padding-right: 2rem; } -.px-\[1px\]{ +.px-\[1px\] { padding-left: 1px; padding-right: 1px; } -.px-\[2px\]{ +.px-\[2px\] { padding-left: 2px; padding-right: 2px; } -.py-1{ +.py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; } -.py-2{ +.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; } -.py-2\.5{ +.py-2\.5 { padding-top: 0.625rem; padding-bottom: 0.625rem; } -.py-3{ +.py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; } -.py-4{ +.py-4 { padding-top: 1rem; padding-bottom: 1rem; } -.py-\[2px\]{ +.py-\[2px\] { padding-top: 2px; padding-bottom: 2px; } -.py-\[3px\]{ +.py-\[3px\] { padding-top: 3px; padding-bottom: 3px; } -.pb-1{ +.pb-1 { padding-bottom: 0.25rem; } -.pb-2{ +.pb-2 { padding-bottom: 0.5rem; } -.pe-10{ +.pe-10 { -webkit-padding-end: 2.5rem; - padding-inline-end: 2.5rem; + padding-inline-end: 2.5rem; } -.pl-1{ +.pl-1 { padding-left: 0.25rem; } -.pl-2{ +.pl-2 { padding-left: 0.5rem; } -.pl-3{ +.pl-3 { padding-left: 0.75rem; } -.pl-4{ +.pl-4 { padding-left: 1rem; } -.pr-0{ +.pr-0 { padding-right: 0px; } -.pr-1{ +.pr-1 { padding-right: 0.25rem; } -.pr-2{ +.pr-2 { padding-right: 0.5rem; } -.pr-4{ +.pr-4 { padding-right: 1rem; } -.pt-0{ +.pt-0 { padding-top: 0px; } -.pt-0\.5{ +.pt-0\.5 { padding-top: 0.125rem; } -.pt-1{ +.pt-1 { padding-top: 0.25rem; } -.pt-10{ +.pt-10 { padding-top: 2.5rem; } -.pt-2{ +.pt-2 { padding-top: 0.5rem; } -.pt-4{ +.pt-4 { padding-top: 1rem; } -.pt-5{ +.pt-5 { padding-top: 1.25rem; } -.pt-8{ +.pt-8 { padding-top: 2rem; } -.text-left{ +.text-left { text-align: left; } -.text-center{ +.text-center { text-align: center; } -.indent-0{ +.indent-0 { text-indent: 0px; } -.font-mono{ +.font-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } -.font-sans{ +.font-sans { font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } -.font-serif{ +.font-serif { font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; } -.text-2xl{ +.text-2xl { font-size: 1.5rem; line-height: 2rem; } -.text-2xs{ +.text-2xs { font-size: 10px; } -.text-3xl{ +.text-3xl { font-size: 1.875rem; line-height: 2.25rem; } -.text-\[10px\]{ +.text-\[10px\] { font-size: 10px; } -.text-\[11px\]{ +.text-\[11px\] { font-size: 11px; } -.text-\[12px\]{ +.text-\[12px\] { font-size: 12px; } -.text-\[18px\]{ +.text-\[18px\] { font-size: 18px; } -.text-\[20px\]{ +.text-\[20px\] { font-size: 20px; } -.text-\[22px\]{ +.text-\[22px\] { font-size: 22px; } -.text-\[24px\]{ +.text-\[24px\] { font-size: 24px; } -.text-\[26px\]{ +.text-\[26px\] { font-size: 26px; } -.text-\[8px\]{ +.text-\[8px\] { font-size: 8px; } -.text-\[9px\]{ +.text-\[9px\] { font-size: 9px; } -.text-base{ +.text-base { font-size: 1rem; line-height: 1.5rem; } -.text-lg{ +.text-lg { font-size: 1.125rem; line-height: 1.75rem; } -.text-sm{ +.text-sm { font-size: 0.875rem; line-height: 1.25rem; } -.text-sm\/none{ +.text-sm\/none { font-size: 0.875rem; line-height: 1; } -.text-xl{ +.text-xl { font-size: 1.25rem; line-height: 1.75rem; } -.text-xs{ +.text-xs { font-size: 0.75rem; line-height: 1rem; } -.font-\[400\]{ +.font-\[400\] { font-weight: 400; } -.font-\[500\]{ +.font-\[500\] { font-weight: 500; } -.font-bold{ +.font-bold { font-weight: 700; } -.font-light{ +.font-light { font-weight: 300; } -.font-medium{ +.font-medium { font-weight: 500; } -.font-normal{ +.font-normal { font-weight: 400; } -.font-semibold{ +.font-semibold { font-weight: 600; } -.uppercase{ +.uppercase { text-transform: uppercase; } -.lowercase{ +.lowercase { text-transform: lowercase; } -.capitalize{ +.capitalize { text-transform: capitalize; } -.leading-5{ +.leading-5 { line-height: 1.25rem; } -.leading-6{ +.leading-6 { line-height: 1.5rem; } -.leading-8{ +.leading-8 { line-height: 2rem; } -.leading-tight{ +.leading-tight { line-height: 1.25; } -.tracking-wide{ +.tracking-wide { letter-spacing: 0.025em; } -.tracking-wider{ +.tracking-wider { letter-spacing: 0.05em; } -.text-\[\#14171a\]{ +.text-\[\#14171a\] { --tw-text-opacity: 1; color: rgb(20 23 26 / var(--tw-text-opacity)); } -.text-\[\#336666\]{ +.text-\[\#336666\] { --tw-text-opacity: 1; color: rgb(51 102 102 / var(--tw-text-opacity)); } -.text-\[\#4B878D\]{ +.text-\[\#4B878D\] { --tw-text-opacity: 1; color: rgb(75 135 141 / var(--tw-text-opacity)); } -.text-\[\#dee3e3\]{ +.text-\[\#dee3e3\] { --tw-text-opacity: 1; color: rgb(222 227 227 / var(--tw-text-opacity)); } -.text-\[\#e6e4e4\]{ +.text-\[\#e6e4e4\] { --tw-text-opacity: 1; color: rgb(230 228 228 / var(--tw-text-opacity)); } -.text-\[greenyellow\]{ +.text-\[greenyellow\] { --tw-text-opacity: 1; color: rgb(173 255 47 / var(--tw-text-opacity)); } -.text-amber-200{ +.text-amber-200 { --tw-text-opacity: 1; color: rgb(253 230 138 / var(--tw-text-opacity)); } -.text-amber-300{ +.text-amber-300 { --tw-text-opacity: 1; color: rgb(252 211 77 / var(--tw-text-opacity)); } -.text-amber-400{ +.text-amber-400 { --tw-text-opacity: 1; color: rgb(251 191 36 / var(--tw-text-opacity)); } -.text-amber-500{ +.text-amber-500 { --tw-text-opacity: 1; color: rgb(245 158 11 / var(--tw-text-opacity)); } -.text-amber-600{ +.text-amber-600 { --tw-text-opacity: 1; color: rgb(217 119 6 / var(--tw-text-opacity)); } -.text-black{ +.text-black { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); } -.text-blue-400{ +.text-blue-400 { --tw-text-opacity: 1; color: rgb(96 165 250 / var(--tw-text-opacity)); } -.text-cyan-400{ +.text-cyan-400 { --tw-text-opacity: 1; color: rgb(34 211 238 / var(--tw-text-opacity)); } -.text-cyan-600{ +.text-cyan-600 { --tw-text-opacity: 1; color: rgb(8 145 178 / var(--tw-text-opacity)); } -.text-gray-100{ +.text-gray-100 { --tw-text-opacity: 1; color: rgb(243 244 246 / var(--tw-text-opacity)); } -.text-gray-200{ +.text-gray-200 { --tw-text-opacity: 1; color: rgb(229 231 235 / var(--tw-text-opacity)); } -.text-gray-300{ +.text-gray-300 { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity)); } -.text-gray-400{ +.text-gray-400 { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } -.text-gray-50{ +.text-gray-50 { --tw-text-opacity: 1; color: rgb(249 250 251 / var(--tw-text-opacity)); } -.text-gray-500{ +.text-gray-500 { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.text-gray-600{ +.text-gray-600 { --tw-text-opacity: 1; color: rgb(75 85 99 / var(--tw-text-opacity)); } -.text-gray-700{ +.text-gray-700 { --tw-text-opacity: 1; color: rgb(55 65 81 / var(--tw-text-opacity)); } -.text-gray-800{ +.text-gray-800 { --tw-text-opacity: 1; color: rgb(31 41 55 / var(--tw-text-opacity)); } -.text-gray-900{ +.text-gray-900 { --tw-text-opacity: 1; color: rgb(17 24 39 / var(--tw-text-opacity)); } -.text-green-400{ +.text-green-400 { --tw-text-opacity: 1; color: rgb(74 222 128 / var(--tw-text-opacity)); } -.text-green-500{ +.text-green-500 { --tw-text-opacity: 1; color: rgb(34 197 94 / var(--tw-text-opacity)); } -.text-green-600{ +.text-green-600 { --tw-text-opacity: 1; color: rgb(22 163 74 / var(--tw-text-opacity)); } -.text-green-700{ +.text-green-700 { --tw-text-opacity: 1; color: rgb(21 128 61 / var(--tw-text-opacity)); } -.text-orange-500{ +.text-orange-500 { --tw-text-opacity: 1; color: rgb(249 115 22 / var(--tw-text-opacity)); } -.text-red-400{ +.text-red-400 { --tw-text-opacity: 1; color: rgb(248 113 113 / var(--tw-text-opacity)); } -.text-red-500{ +.text-red-500 { --tw-text-opacity: 1; color: rgb(239 68 68 / var(--tw-text-opacity)); } -.text-red-600{ +.text-red-600 { --tw-text-opacity: 1; color: rgb(220 38 38 / var(--tw-text-opacity)); } -.text-red-700{ +.text-red-700 { --tw-text-opacity: 1; color: rgb(185 28 28 / var(--tw-text-opacity)); } -.text-red-800{ +.text-red-800 { --tw-text-opacity: 1; color: rgb(153 27 27 / var(--tw-text-opacity)); } -.text-teal-400{ +.text-teal-400 { --tw-text-opacity: 1; color: rgb(45 212 191 / var(--tw-text-opacity)); } -.text-teal-500{ +.text-teal-500 { --tw-text-opacity: 1; color: rgb(20 184 166 / var(--tw-text-opacity)); } -.text-teal-600{ +.text-teal-600 { --tw-text-opacity: 1; color: rgb(13 148 136 / var(--tw-text-opacity)); } -.text-teal-700{ +.text-teal-700 { --tw-text-opacity: 1; color: rgb(15 118 110 / var(--tw-text-opacity)); } -.text-white{ +.text-white { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity)); } -.text-yellow-400{ +.text-yellow-400 { --tw-text-opacity: 1; color: rgb(250 204 21 / var(--tw-text-opacity)); } -.text-yellow-500{ +.text-yellow-500 { --tw-text-opacity: 1; color: rgb(234 179 8 / var(--tw-text-opacity)); } -.placeholder-gray-400\/70::-webkit-input-placeholder{ +.placeholder-gray-400\/70::-webkit-input-placeholder { color: rgb(156 163 175 / 0.7); } -.placeholder-gray-400\/70::-moz-placeholder{ +.placeholder-gray-400\/70::-moz-placeholder { color: rgb(156 163 175 / 0.7); } -.placeholder-gray-400\/70:-ms-input-placeholder{ +.placeholder-gray-400\/70:-ms-input-placeholder { color: rgb(156 163 175 / 0.7); } -.placeholder-gray-400\/70::-ms-input-placeholder{ +.placeholder-gray-400\/70::-ms-input-placeholder { color: rgb(156 163 175 / 0.7); } -.placeholder-gray-400\/70::placeholder{ +.placeholder-gray-400\/70::placeholder { color: rgb(156 163 175 / 0.7); } -.placeholder-gray-500::-webkit-input-placeholder{ +.placeholder-gray-500::-webkit-input-placeholder { --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); } -.placeholder-gray-500::-moz-placeholder{ +.placeholder-gray-500::-moz-placeholder { --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); } -.placeholder-gray-500:-ms-input-placeholder{ +.placeholder-gray-500:-ms-input-placeholder { --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); } -.placeholder-gray-500::-ms-input-placeholder{ +.placeholder-gray-500::-ms-input-placeholder { --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); } -.placeholder-gray-500::placeholder{ +.placeholder-gray-500::placeholder { --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); } -.placeholder-red-500::-webkit-input-placeholder{ +.placeholder-red-500::-webkit-input-placeholder { --tw-placeholder-opacity: 1; color: rgb(239 68 68 / var(--tw-placeholder-opacity)); } -.placeholder-red-500::-moz-placeholder{ +.placeholder-red-500::-moz-placeholder { --tw-placeholder-opacity: 1; color: rgb(239 68 68 / var(--tw-placeholder-opacity)); } -.placeholder-red-500:-ms-input-placeholder{ +.placeholder-red-500:-ms-input-placeholder { --tw-placeholder-opacity: 1; color: rgb(239 68 68 / var(--tw-placeholder-opacity)); } -.placeholder-red-500::-ms-input-placeholder{ +.placeholder-red-500::-ms-input-placeholder { --tw-placeholder-opacity: 1; color: rgb(239 68 68 / var(--tw-placeholder-opacity)); } -.placeholder-red-500::placeholder{ +.placeholder-red-500::placeholder { --tw-placeholder-opacity: 1; color: rgb(239 68 68 / var(--tw-placeholder-opacity)); } -.opacity-0{ +.opacity-0 { opacity: 0; } -.opacity-100{ +.opacity-100 { opacity: 1; } -.opacity-25{ +.opacity-25 { opacity: 0.25; } -.opacity-30{ +.opacity-30 { opacity: 0.3; } -.opacity-40{ +.opacity-40 { opacity: 0.4; } -.opacity-45{ +.opacity-45 { opacity: 0.45; } -.opacity-50{ +.opacity-50 { opacity: 0.5; } -.opacity-65{ +.opacity-65 { opacity: 0.65; } -.opacity-70{ +.opacity-70 { opacity: 0.7; } -.opacity-80{ +.opacity-80 { opacity: 0.8; } -.shadow{ +.shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-2xl{ +.shadow-2xl { --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-lg{ +.shadow-lg { --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-md{ +.shadow-md { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-none{ +.shadow-none { --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-sm{ +.shadow-sm { --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-xl{ +.shadow-xl { --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-\[\#101010\]{ +.shadow-\[\#101010\] { --tw-shadow-color: #101010; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#111010\]{ +.shadow-\[\#111010\] { --tw-shadow-color: #111010; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#141414\]{ +.shadow-\[\#141414\] { --tw-shadow-color: #141414; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#141516\]{ +.shadow-\[\#141516\] { --tw-shadow-color: #141516; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#182020\]{ +.shadow-\[\#182020\] { --tw-shadow-color: #182020; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#191a1b\]{ +.shadow-\[\#191a1b\] { --tw-shadow-color: #191a1b; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#1c3634\]{ +.shadow-\[\#1c3634\] { --tw-shadow-color: #1c3634; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#1e2b2b\]{ +.shadow-\[\#1e2b2b\] { --tw-shadow-color: #1e2b2b; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#1f2021\]{ +.shadow-\[\#1f2021\] { --tw-shadow-color: #1f2021; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#23272a\]{ +.shadow-\[\#23272a\] { --tw-shadow-color: #23272a; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#242c29\]{ +.shadow-\[\#242c29\] { --tw-shadow-color: #242c29; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#252525\]{ +.shadow-\[\#252525\] { --tw-shadow-color: #252525; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#303232\]{ +.shadow-\[\#303232\] { --tw-shadow-color: #303232; --tw-shadow: var(--tw-shadow-colored); } -.shadow-\[\#3a3a3b\]{ +.shadow-\[\#3a3a3b\] { --tw-shadow-color: #3a3a3b; --tw-shadow: var(--tw-shadow-colored); } -.shadow-black{ +.shadow-black { --tw-shadow-color: #000; --tw-shadow: var(--tw-shadow-colored); } -.shadow-gray-600{ +.shadow-gray-600 { --tw-shadow-color: #4b5563; --tw-shadow: var(--tw-shadow-colored); } -.shadow-gray-800{ +.shadow-gray-800 { --tw-shadow-color: #1f2937; --tw-shadow: var(--tw-shadow-colored); } -.shadow-zinc-800{ +.shadow-zinc-800 { --tw-shadow-color: #27272a; --tw-shadow: var(--tw-shadow-colored); } -.outline-none{ +.outline-none { outline: 2px solid transparent; outline-offset: 2px; } -.outline{ +.outline { outline-style: solid; } -.outline-0{ +.outline-0 { outline-width: 0px; } -.outline-transparent{ +.outline-transparent { outline-color: transparent; } -.ring-1{ +.ring-1 { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } -.ring-black{ +.ring-black { --tw-ring-opacity: 1; --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity)); } -.ring-opacity-5{ +.ring-opacity-5 { --tw-ring-opacity: 0.05; } -.invert{ +.invert { --tw-invert: invert(100%); - -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) + var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) + var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -.filter{ - -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +.filter { + -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) + var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) + var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -.filter-none{ +.filter-none { -webkit-filter: none; - filter: none; -} - -.transition{ - -webkit-transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, -webkit-box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, -webkit-box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; + filter: none; +} + +.transition { + -webkit-transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, -webkit-box-shadow, + -webkit-transform, -webkit-filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, -webkit-box-shadow, + -webkit-transform, -webkit-filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, + backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, + backdrop-filter, -webkit-box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -webkit-transition-duration: 150ms; - transition-duration: 150ms; + transition-duration: 150ms; } -.transition-all{ +.transition-all { -webkit-transition-property: all; transition-property: all; -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -webkit-transition-duration: 150ms; - transition-duration: 150ms; + transition-duration: 150ms; } -.transition-colors{ +.transition-colors { -webkit-transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -webkit-transition-duration: 150ms; - transition-duration: 150ms; + transition-duration: 150ms; } -.transition-transform{ +.transition-transform { -webkit-transition-property: -webkit-transform; transition-property: -webkit-transform; transition-property: transform; transition-property: transform, -webkit-transform; -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -webkit-transition-duration: 150ms; - transition-duration: 150ms; + transition-duration: 150ms; } -.delay-100{ +.delay-100 { -webkit-transition-delay: 100ms; - transition-delay: 100ms; + transition-delay: 100ms; } -.duration-100{ +.duration-100 { -webkit-transition-duration: 100ms; - transition-duration: 100ms; + transition-duration: 100ms; } -.duration-1000{ +.duration-1000 { -webkit-transition-duration: 1000ms; - transition-duration: 1000ms; + transition-duration: 1000ms; } -.duration-150{ +.duration-150 { -webkit-transition-duration: 150ms; - transition-duration: 150ms; + transition-duration: 150ms; } -.duration-200{ +.duration-200 { -webkit-transition-duration: 200ms; - transition-duration: 200ms; + transition-duration: 200ms; } -.duration-300{ +.duration-300 { -webkit-transition-duration: 300ms; - transition-duration: 300ms; + transition-duration: 300ms; } -.duration-500{ +.duration-500 { -webkit-transition-duration: 500ms; - transition-duration: 500ms; + transition-duration: 500ms; } -.ease-in{ +.ease-in { -webkit-transition-timing-function: cubic-bezier(0.4, 0, 1, 1); - transition-timing-function: cubic-bezier(0.4, 0, 1, 1); + transition-timing-function: cubic-bezier(0.4, 0, 1, 1); } -.ease-in-out{ +.ease-in-out { -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } -.ease-out{ +.ease-out { -webkit-transition-timing-function: cubic-bezier(0, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } -.scrollbar::-webkit-scrollbar-track{ +.scrollbar::-webkit-scrollbar-track { background-color: var(--scrollbar-track); border-radius: var(--scrollbar-track-radius); } -.scrollbar::-webkit-scrollbar-track:hover{ +.scrollbar::-webkit-scrollbar-track:hover { background-color: var(--scrollbar-track-hover, var(--scrollbar-track)); } -.scrollbar::-webkit-scrollbar-track:active{ +.scrollbar::-webkit-scrollbar-track:active { background-color: var(--scrollbar-track-active, var(--scrollbar-track-hover, var(--scrollbar-track))); } -.scrollbar::-webkit-scrollbar-thumb{ +.scrollbar::-webkit-scrollbar-thumb { background-color: var(--scrollbar-thumb); border-radius: var(--scrollbar-thumb-radius); } -.scrollbar::-webkit-scrollbar-thumb:hover{ +.scrollbar::-webkit-scrollbar-thumb:hover { background-color: var(--scrollbar-thumb-hover, var(--scrollbar-thumb)); } -.scrollbar::-webkit-scrollbar-thumb:active{ +.scrollbar::-webkit-scrollbar-thumb:active { background-color: var(--scrollbar-thumb-active, var(--scrollbar-thumb-hover, var(--scrollbar-thumb))); } -.scrollbar::-webkit-scrollbar-corner{ +.scrollbar::-webkit-scrollbar-corner { background-color: var(--scrollbar-corner); border-radius: var(--scrollbar-corner-radius); } -.scrollbar::-webkit-scrollbar-corner:hover{ +.scrollbar::-webkit-scrollbar-corner:hover { background-color: var(--scrollbar-corner-hover, var(--scrollbar-corner)); } -.scrollbar::-webkit-scrollbar-corner:active{ +.scrollbar::-webkit-scrollbar-corner:active { background-color: var(--scrollbar-corner-active, var(--scrollbar-corner-hover, var(--scrollbar-corner))); } -.scrollbar{ +.scrollbar { scrollbar-width: auto; scrollbar-color: var(--scrollbar-thumb, initial) var(--scrollbar-track, initial); } -.scrollbar::-webkit-scrollbar{ +.scrollbar::-webkit-scrollbar { display: block; width: var(--scrollbar-width, 16px); height: var(--scrollbar-height, 16px); } -.scrollbar-thin::-webkit-scrollbar-track{ +.scrollbar-thin::-webkit-scrollbar-track { background-color: var(--scrollbar-track); border-radius: var(--scrollbar-track-radius); } -.scrollbar-thin::-webkit-scrollbar-track:hover{ +.scrollbar-thin::-webkit-scrollbar-track:hover { background-color: var(--scrollbar-track-hover, var(--scrollbar-track)); } -.scrollbar-thin::-webkit-scrollbar-track:active{ +.scrollbar-thin::-webkit-scrollbar-track:active { background-color: var(--scrollbar-track-active, var(--scrollbar-track-hover, var(--scrollbar-track))); } -.scrollbar-thin::-webkit-scrollbar-thumb{ +.scrollbar-thin::-webkit-scrollbar-thumb { background-color: var(--scrollbar-thumb); border-radius: var(--scrollbar-thumb-radius); } -.scrollbar-thin::-webkit-scrollbar-thumb:hover{ +.scrollbar-thin::-webkit-scrollbar-thumb:hover { background-color: var(--scrollbar-thumb-hover, var(--scrollbar-thumb)); } -.scrollbar-thin::-webkit-scrollbar-thumb:active{ +.scrollbar-thin::-webkit-scrollbar-thumb:active { background-color: var(--scrollbar-thumb-active, var(--scrollbar-thumb-hover, var(--scrollbar-thumb))); } -.scrollbar-thin::-webkit-scrollbar-corner{ +.scrollbar-thin::-webkit-scrollbar-corner { background-color: var(--scrollbar-corner); border-radius: var(--scrollbar-corner-radius); } -.scrollbar-thin::-webkit-scrollbar-corner:hover{ +.scrollbar-thin::-webkit-scrollbar-corner:hover { background-color: var(--scrollbar-corner-hover, var(--scrollbar-corner)); } -.scrollbar-thin::-webkit-scrollbar-corner:active{ +.scrollbar-thin::-webkit-scrollbar-corner:active { background-color: var(--scrollbar-corner-active, var(--scrollbar-corner-hover, var(--scrollbar-corner))); } -.scrollbar-thin{ +.scrollbar-thin { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb, initial) var(--scrollbar-track, initial); } -.scrollbar-thin::-webkit-scrollbar{ +.scrollbar-thin::-webkit-scrollbar { display: block; width: 8px; height: 8px; } -.scrollbar-track-gray-100{ +.scrollbar-track-gray-100 { --scrollbar-track: #f3f4f6 !important; } -.scrollbar-track-gray-800{ +.scrollbar-track-gray-800 { --scrollbar-track: #1f2937 !important; } -.scrollbar-track-transparent{ +.scrollbar-track-transparent { --scrollbar-track: transparent !important; } -.scrollbar-thumb-gray-300{ +.scrollbar-thumb-gray-300 { --scrollbar-thumb: #d1d5db !important; } -.scrollbar-thumb-gray-500{ +.scrollbar-thumb-gray-500 { --scrollbar-thumb: #6b7280 !important; } -.scrollbar-thumb-teal-800{ +.scrollbar-thumb-teal-800 { --scrollbar-thumb: #115e59 !important; } -.\[-webkit-tap-highlight-color\:_transparent\]{ +.\[-webkit-tap-highlight-color\:_transparent\] { -webkit-tap-highlight-color: transparent; } @@ -5292,755 +5338,775 @@ html body { margin: 0; font-family: "Noto Sans", sans-serif; -webkit-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; background-color: rgb(31, 31, 31); } -.placeholder\:text-gray-400::-webkit-input-placeholder{ +.placeholder\:text-gray-400::-webkit-input-placeholder { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } -.placeholder\:text-gray-400::-moz-placeholder{ +.placeholder\:text-gray-400::-moz-placeholder { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } -.placeholder\:text-gray-400:-ms-input-placeholder{ +.placeholder\:text-gray-400:-ms-input-placeholder { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } -.placeholder\:text-gray-400::-ms-input-placeholder{ +.placeholder\:text-gray-400::-ms-input-placeholder { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } -.placeholder\:text-gray-400::placeholder{ +.placeholder\:text-gray-400::placeholder { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } -.placeholder\:text-gray-500::-webkit-input-placeholder{ +.placeholder\:text-gray-500::-webkit-input-placeholder { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.placeholder\:text-gray-500::-moz-placeholder{ +.placeholder\:text-gray-500::-moz-placeholder { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.placeholder\:text-gray-500:-ms-input-placeholder{ +.placeholder\:text-gray-500:-ms-input-placeholder { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.placeholder\:text-gray-500::-ms-input-placeholder{ +.placeholder\:text-gray-500::-ms-input-placeholder { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.placeholder\:text-gray-500::placeholder{ +.placeholder\:text-gray-500::placeholder { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.after\:absolute::after{ +.after\:absolute::after { content: var(--tw-content); position: absolute; } -.after\:left-\[2px\]::after{ +.after\:left-\[2px\]::after { content: var(--tw-content); left: 2px; } -.after\:top-0::after{ +.after\:top-0::after { content: var(--tw-content); top: 0px; } -.after\:top-0\.5::after{ +.after\:top-0\.5::after { content: var(--tw-content); top: 0.125rem; } -.after\:h-4::after{ +.after\:h-4::after { content: var(--tw-content); height: 1rem; } -.after\:w-4::after{ +.after\:w-4::after { content: var(--tw-content); width: 1rem; } -.after\:rounded-full::after{ +.after\:rounded-full::after { content: var(--tw-content); border-radius: 9999px; } -.after\:border::after{ +.after\:border::after { content: var(--tw-content); border-width: 1px; } -.after\:border-gray-300::after{ +.after\:border-gray-300::after { content: var(--tw-content); --tw-border-opacity: 1; border-color: rgb(209 213 219 / var(--tw-border-opacity)); } -.after\:bg-white::after{ +.after\:bg-white::after { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.after\:transition-all::after{ +.after\:transition-all::after { content: var(--tw-content); -webkit-transition-property: all; transition-property: all; -webkit-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -webkit-transition-duration: 150ms; - transition-duration: 150ms; + transition-duration: 150ms; } -.after\:content-\[\'\'\]::after{ - --tw-content: ''; +.after\:content-\[\'\'\]::after { + --tw-content: ""; content: var(--tw-content); } -.peer:checked ~ .peer-checked\:start-6{ +.peer:checked ~ .peer-checked\:start-6 { inset-inline-start: 1.5rem; } -.peer:checked ~ .peer-checked\:border-green-600{ +.peer:checked ~ .peer-checked\:border-green-600 { --tw-border-opacity: 1; border-color: rgb(22 163 74 / var(--tw-border-opacity)); } -.peer:checked ~ .peer-checked\:bg-green-500{ +.peer:checked ~ .peer-checked\:bg-green-500 { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } -.peer:checked ~ .peer-checked\:bg-green-600{ +.peer:checked ~ .peer-checked\:bg-green-600 { --tw-bg-opacity: 1; background-color: rgb(22 163 74 / var(--tw-bg-opacity)); } -.peer:checked ~ .peer-checked\:text-green-600{ +.peer:checked ~ .peer-checked\:text-green-600 { --tw-text-opacity: 1; color: rgb(22 163 74 / var(--tw-text-opacity)); } -.peer:checked ~ .peer-checked\:shadow-inner{ +.peer:checked ~ .peer-checked\:shadow-inner { --tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); --tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.peer:checked ~ .peer-checked\:shadow-gray-600{ +.peer:checked ~ .peer-checked\:shadow-gray-600 { --tw-shadow-color: #4b5563; --tw-shadow: var(--tw-shadow-colored); } -.peer:checked ~ .peer-checked\:after\:translate-x-7::after{ +.peer:checked ~ .peer-checked\:after\:translate-x-7::after { content: var(--tw-content); --tw-translate-x: 1.75rem; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.peer:checked ~ .peer-checked\:after\:border-white::after{ +.peer:checked ~ .peer-checked\:after\:border-white::after { content: var(--tw-content); --tw-border-opacity: 1; border-color: rgb(255 255 255 / var(--tw-border-opacity)); } -.hover\:scale-105:hover{ +.hover\:scale-105:hover { --tw-scale-x: 1.05; --tw-scale-y: 1.05; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.hover\:scale-110:hover{ +.hover\:scale-110:hover { --tw-scale-x: 1.1; --tw-scale-y: 1.1; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.hover\:scale-125:hover{ +.hover\:scale-125:hover { --tw-scale-x: 1.25; --tw-scale-y: 1.25; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.hover\:scale-95:hover{ - --tw-scale-x: .95; - --tw-scale-y: .95; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.hover\:scale-95:hover { + --tw-scale-x: 0.95; + --tw-scale-y: 0.95; + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.hover\:overflow-y-auto:hover{ +.hover\:overflow-y-auto:hover { overflow-y: auto; } -.hover\:scroll-auto:hover{ +.hover\:scroll-auto:hover { scroll-behavior: auto; } -.hover\:border:hover{ +.hover\:border:hover { border-width: 1px; } -.hover\:border-\[\#3f4851\]:hover{ +.hover\:border-\[\#3f4851\]:hover { --tw-border-opacity: 1; border-color: rgb(63 72 81 / var(--tw-border-opacity)); } -.hover\:border-\[\#4d7575\]:hover{ +.hover\:border-\[\#4d7575\]:hover { --tw-border-opacity: 1; border-color: rgb(77 117 117 / var(--tw-border-opacity)); } -.hover\:border-amber-300:hover{ +.hover\:border-amber-300:hover { --tw-border-opacity: 1; border-color: rgb(252 211 77 / var(--tw-border-opacity)); } -.hover\:border-blue-400:hover{ +.hover\:border-blue-400:hover { --tw-border-opacity: 1; border-color: rgb(96 165 250 / var(--tw-border-opacity)); } -.hover\:border-gray-100:hover{ +.hover\:border-gray-100:hover { --tw-border-opacity: 1; border-color: rgb(243 244 246 / var(--tw-border-opacity)); } -.hover\:border-gray-200:hover{ +.hover\:border-gray-200:hover { --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity)); } -.hover\:border-gray-300:hover{ +.hover\:border-gray-300:hover { --tw-border-opacity: 1; border-color: rgb(209 213 219 / var(--tw-border-opacity)); } -.hover\:border-gray-500:hover{ +.hover\:border-gray-500:hover { --tw-border-opacity: 1; border-color: rgb(107 114 128 / var(--tw-border-opacity)); } -.hover\:border-gray-600:hover{ +.hover\:border-gray-600:hover { --tw-border-opacity: 1; border-color: rgb(75 85 99 / var(--tw-border-opacity)); } -.hover\:border-red-500:hover{ +.hover\:border-red-500:hover { --tw-border-opacity: 1; border-color: rgb(239 68 68 / var(--tw-border-opacity)); } -.hover\:border-teal-200:hover{ +.hover\:border-teal-200:hover { --tw-border-opacity: 1; border-color: rgb(153 246 228 / var(--tw-border-opacity)); } -.hover\:border-teal-500:hover{ +.hover\:border-teal-500:hover { --tw-border-opacity: 1; border-color: rgb(20 184 166 / var(--tw-border-opacity)); } -.hover\:border-teal-600:hover{ +.hover\:border-teal-600:hover { --tw-border-opacity: 1; border-color: rgb(13 148 136 / var(--tw-border-opacity)); } -.hover\:bg-\[\#212325\]:hover{ +.hover\:bg-\[\#212325\]:hover { --tw-bg-opacity: 1; background-color: rgb(33 35 37 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#222425\]:hover{ +.hover\:bg-\[\#222425\]:hover { --tw-bg-opacity: 1; background-color: rgb(34 36 37 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#224141\]:hover{ +.hover\:bg-\[\#224141\]:hover { --tw-bg-opacity: 1; background-color: rgb(34 65 65 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#23272a\]:hover{ +.hover\:bg-\[\#23272a\]:hover { --tw-bg-opacity: 1; background-color: rgb(35 39 42 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#234545\]:hover{ +.hover\:bg-\[\#234545\]:hover { --tw-bg-opacity: 1; background-color: rgb(35 69 69 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#243535\]:hover{ +.hover\:bg-\[\#243535\]:hover { --tw-bg-opacity: 1; background-color: rgb(36 53 53 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#244343\]:hover{ +.hover\:bg-\[\#244343\]:hover { --tw-bg-opacity: 1; background-color: rgb(36 67 67 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#264e4e\]:hover{ +.hover\:bg-\[\#264e4e\]:hover { --tw-bg-opacity: 1; background-color: rgb(38 78 78 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#282a2d\]:hover{ +.hover\:bg-\[\#282a2d\]:hover { --tw-bg-opacity: 1; background-color: rgb(40 42 45 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#2b3034\]:hover{ +.hover\:bg-\[\#2b3034\]:hover { --tw-bg-opacity: 1; background-color: rgb(43 48 52 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#325e5a\]:hover{ +.hover\:bg-\[\#325e5a\]:hover { --tw-bg-opacity: 1; background-color: rgb(50 94 90 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#336666\]:hover{ +.hover\:bg-\[\#336666\]:hover { --tw-bg-opacity: 1; background-color: rgb(51 102 102 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#374045\]:hover{ +.hover\:bg-\[\#374045\]:hover { --tw-bg-opacity: 1; background-color: rgb(55 64 69 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#383c3f\]:hover{ +.hover\:bg-\[\#383c3f\]:hover { --tw-bg-opacity: 1; background-color: rgb(56 60 63 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#3c434a\]:hover{ +.hover\:bg-\[\#3c434a\]:hover { --tw-bg-opacity: 1; background-color: rgb(60 67 74 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#447a75\]:hover{ +.hover\:bg-\[\#447a75\]:hover { --tw-bg-opacity: 1; background-color: rgb(68 122 117 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#4c7960\]:hover{ +.hover\:bg-\[\#4c7960\]:hover { --tw-bg-opacity: 1; background-color: rgb(76 121 96 / var(--tw-bg-opacity)); } -.hover\:bg-\[\#4d7575\]:hover{ +.hover\:bg-\[\#4d7575\]:hover { --tw-bg-opacity: 1; background-color: rgb(77 117 117 / var(--tw-bg-opacity)); } -.hover\:bg-black:hover{ +.hover\:bg-black:hover { --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); } -.hover\:bg-blue-100:hover{ +.hover\:bg-blue-100:hover { --tw-bg-opacity: 1; background-color: rgb(219 234 254 / var(--tw-bg-opacity)); } -.hover\:bg-blue-300:hover{ +.hover\:bg-blue-300:hover { --tw-bg-opacity: 1; background-color: rgb(147 197 253 / var(--tw-bg-opacity)); } -.hover\:bg-blue-400:hover{ +.hover\:bg-blue-400:hover { --tw-bg-opacity: 1; background-color: rgb(96 165 250 / var(--tw-bg-opacity)); } -.hover\:bg-blue-500:hover{ +.hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } -.hover\:bg-cyan-600:hover{ +.hover\:bg-cyan-600:hover { --tw-bg-opacity: 1; background-color: rgb(8 145 178 / var(--tw-bg-opacity)); } -.hover\:bg-gray-100:hover{ +.hover\:bg-gray-100:hover { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } -.hover\:bg-gray-300:hover{ +.hover\:bg-gray-300:hover { --tw-bg-opacity: 1; background-color: rgb(209 213 219 / var(--tw-bg-opacity)); } -.hover\:bg-gray-500:hover{ +.hover\:bg-gray-500:hover { --tw-bg-opacity: 1; background-color: rgb(107 114 128 / var(--tw-bg-opacity)); } -.hover\:bg-gray-600:hover{ +.hover\:bg-gray-600:hover { --tw-bg-opacity: 1; background-color: rgb(75 85 99 / var(--tw-bg-opacity)); } -.hover\:bg-gray-700:hover{ +.hover\:bg-gray-700:hover { --tw-bg-opacity: 1; background-color: rgb(55 65 81 / var(--tw-bg-opacity)); } -.hover\:bg-green-600:hover{ +.hover\:bg-green-600:hover { --tw-bg-opacity: 1; background-color: rgb(22 163 74 / var(--tw-bg-opacity)); } -.hover\:bg-lime-900:hover{ +.hover\:bg-lime-900:hover { --tw-bg-opacity: 1; background-color: rgb(54 83 20 / var(--tw-bg-opacity)); } -.hover\:bg-red-500:hover{ +.hover\:bg-red-500:hover { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } -.hover\:bg-red-600:hover{ +.hover\:bg-red-600:hover { --tw-bg-opacity: 1; background-color: rgb(220 38 38 / var(--tw-bg-opacity)); } -.hover\:bg-red-700:hover{ +.hover\:bg-red-700:hover { --tw-bg-opacity: 1; background-color: rgb(185 28 28 / var(--tw-bg-opacity)); } -.hover\:bg-red-800:hover{ +.hover\:bg-red-800:hover { --tw-bg-opacity: 1; background-color: rgb(153 27 27 / var(--tw-bg-opacity)); } -.hover\:bg-red-950:hover{ +.hover\:bg-red-950:hover { --tw-bg-opacity: 1; background-color: rgb(69 10 10 / var(--tw-bg-opacity)); } -.hover\:bg-slate-300:hover{ +.hover\:bg-slate-300:hover { --tw-bg-opacity: 1; background-color: rgb(203 213 225 / var(--tw-bg-opacity)); } -.hover\:bg-teal-600:hover{ +.hover\:bg-teal-600:hover { --tw-bg-opacity: 1; background-color: rgb(13 148 136 / var(--tw-bg-opacity)); } -.hover\:bg-teal-700:hover{ +.hover\:bg-teal-700:hover { --tw-bg-opacity: 1; background-color: rgb(15 118 110 / var(--tw-bg-opacity)); } -.hover\:bg-teal-800:hover{ +.hover\:bg-teal-800:hover { --tw-bg-opacity: 1; background-color: rgb(17 94 89 / var(--tw-bg-opacity)); } -.hover\:bg-teal-900:hover{ +.hover\:bg-teal-900:hover { --tw-bg-opacity: 1; background-color: rgb(19 78 74 / var(--tw-bg-opacity)); } -.hover\:bg-teal-950:hover{ +.hover\:bg-teal-950:hover { --tw-bg-opacity: 1; background-color: rgb(4 47 46 / var(--tw-bg-opacity)); } -.hover\:bg-opacity-10:hover{ +.hover\:bg-opacity-10:hover { --tw-bg-opacity: 0.1; } -.hover\:text-black:hover{ +.hover\:text-black:hover { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); } -.hover\:text-gray-100:hover{ +.hover\:text-gray-100:hover { --tw-text-opacity: 1; color: rgb(243 244 246 / var(--tw-text-opacity)); } -.hover\:text-gray-200:hover{ +.hover\:text-gray-200:hover { --tw-text-opacity: 1; color: rgb(229 231 235 / var(--tw-text-opacity)); } -.hover\:text-gray-300:hover{ +.hover\:text-gray-300:hover { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity)); } -.hover\:text-gray-700:hover{ +.hover\:text-gray-700:hover { --tw-text-opacity: 1; color: rgb(55 65 81 / var(--tw-text-opacity)); } -.hover\:text-teal-500:hover{ +.hover\:text-teal-500:hover { --tw-text-opacity: 1; color: rgb(20 184 166 / var(--tw-text-opacity)); } -.hover\:text-white:hover{ +.hover\:text-white:hover { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity)); } -.hover\:shadow-2xl:hover{ +.hover\:shadow-2xl:hover { --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.hover\:shadow-lg:hover{ +.hover\:shadow-lg:hover { --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.hover\:shadow-md:hover{ +.hover\:shadow-md:hover { --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.hover\:shadow-sm:hover{ +.hover\:shadow-sm:hover { --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.hover\:shadow-\[\#050505\]:hover{ +.hover\:shadow-\[\#050505\]:hover { --tw-shadow-color: #050505; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#101214\]:hover{ +.hover\:shadow-\[\#101214\]:hover { --tw-shadow-color: #101214; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#191a1a\]:hover{ +.hover\:shadow-\[\#191a1a\]:hover { --tw-shadow-color: #191a1a; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#1b1c1c\]:hover{ +.hover\:shadow-\[\#1b1c1c\]:hover { --tw-shadow-color: #1b1c1c; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#1b1d20\]:hover{ +.hover\:shadow-\[\#1b1d20\]:hover { --tw-shadow-color: #1b1d20; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#1e2a29\]:hover{ +.hover\:shadow-\[\#1e2a29\]:hover { --tw-shadow-color: #1e2a29; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#303232\]:hover{ +.hover\:shadow-\[\#303232\]:hover { --tw-shadow-color: #303232; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-\[\#3a3a3b\]:hover{ +.hover\:shadow-\[\#3a3a3b\]:hover { --tw-shadow-color: #3a3a3b; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-black:hover{ +.hover\:shadow-black:hover { --tw-shadow-color: #000; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-gray-800:hover{ +.hover\:shadow-gray-800:hover { --tw-shadow-color: #1f2937; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-gray-900:hover{ +.hover\:shadow-gray-900:hover { --tw-shadow-color: #111827; --tw-shadow: var(--tw-shadow-colored); } -.hover\:shadow-gray-950:hover{ +.hover\:shadow-gray-950:hover { --tw-shadow-color: #030712; --tw-shadow: var(--tw-shadow-colored); } -.hover\:brightness-110:hover{ +.hover\:brightness-110:hover { --tw-brightness: brightness(1.1); - -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) + var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) + var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -.hover\:scrollbar-thumb-teal-800{ +.hover\:scrollbar-thumb-teal-800 { --scrollbar-thumb-hover: #115e59 !important; } -.focus\:border-blue-500:focus{ +.focus\:border-blue-500:focus { --tw-border-opacity: 1; border-color: rgb(59 130 246 / var(--tw-border-opacity)); } -.focus\:border-teal-500:focus{ +.focus\:border-teal-500:focus { --tw-border-opacity: 1; border-color: rgb(20 184 166 / var(--tw-border-opacity)); } -.focus\:outline-none:focus{ +.focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; } -.focus\:ring:focus{ +.focus\:ring:focus { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); -webkit-box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } -.focus\:ring-blue-300:focus{ +.focus\:ring-blue-300:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity)); } -.focus\:ring-opacity-40:focus{ +.focus\:ring-opacity-40:focus { --tw-ring-opacity: 0.4; } -.active\:scale-100:active{ +.active\:scale-100:active { --tw-scale-x: 1; --tw-scale-y: 1; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.active\:scale-75:active{ - --tw-scale-x: .75; - --tw-scale-y: .75; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.active\:scale-75:active { + --tw-scale-x: 0.75; + --tw-scale-y: 0.75; + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.active\:scale-90:active{ - --tw-scale-x: .9; - --tw-scale-y: .9; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.active\:scale-90:active { + --tw-scale-x: 0.9; + --tw-scale-y: 0.9; + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.active\:scale-95:active{ - --tw-scale-x: .95; - --tw-scale-y: .95; - -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +.active\:scale-95:active { + --tw-scale-x: 0.95; + --tw-scale-y: 0.95; + -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) + skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.active\:border-none:active{ +.active\:border-none:active { border-style: none; } -.active\:bg-\[\#1b1c1c\]:active{ +.active\:bg-\[\#1b1c1c\]:active { --tw-bg-opacity: 1; background-color: rgb(27 28 28 / var(--tw-bg-opacity)); } -.active\:shadow-none:active{ +.active\:shadow-none:active { --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; -webkit-box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.active\:shadow-gray-800:active{ +.active\:shadow-gray-800:active { --tw-shadow-color: #1f2937; --tw-shadow: var(--tw-shadow-colored); } -@media (min-width: 640px){ - .sm\:text-sm{ +@media (min-width: 640px) { + .sm\:text-sm { font-size: 0.875rem; line-height: 1.25rem; } } -@media (min-width: 768px){ - .md\:mb-0{ +@media (min-width: 768px) { + .md\:mb-0 { margin-bottom: 0px; } } -.rtl\:left-0:where([dir="rtl"], [dir="rtl"] *){ +.rtl\:left-0:where([dir="rtl"], [dir="rtl"] *) { left: 0px; } -.rtl\:right-auto:where([dir="rtl"], [dir="rtl"] *){ +.rtl\:right-auto:where([dir="rtl"], [dir="rtl"] *) { right: auto; } -@media (prefers-color-scheme: dark){ - .dark\:text-gray-300{ +@media (prefers-color-scheme: dark) { + .dark\:text-gray-300 { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity)); } - .dark\:text-gray-400{ + .dark\:text-gray-400 { --tw-text-opacity: 1; color: rgb(156 163 175 / var(--tw-text-opacity)); } - .dark\:hover\:bg-gray-700:hover{ + .dark\:hover\:bg-gray-700:hover { --tw-bg-opacity: 1; background-color: rgb(55 65 81 / var(--tw-bg-opacity)); } - .dark\:hover\:text-white:hover{ + .dark\:hover\:text-white:hover { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity)); } } -.\[\&\:checked_\+_span_svg\[data-checked-icon\]\]\:block:checked + span svg[data-checked-icon]{ +.\[\&\:checked_\+_span_svg\[data-checked-icon\]\]\:block:checked + span svg[data-checked-icon] { display: block; } -.\[\&\:checked_\+_span_svg\[data-unchecked-icon\]\]\:hidden:checked + span svg[data-unchecked-icon]{ +.\[\&\:checked_\+_span_svg\[data-unchecked-icon\]\]\:hidden:checked + span svg[data-unchecked-icon] { display: none; } diff --git a/launcher/src/StereumUpdater.js b/launcher/src/StereumUpdater.js index 73e9902ec2..0c28a60e00 100644 --- a/launcher/src/StereumUpdater.js +++ b/launcher/src/StereumUpdater.js @@ -1,78 +1,84 @@ import { autoUpdater } from "electron-updater"; import { app, BrowserWindow } from "electron"; - export class StereumUpdater { - constructor(logger, createWindow) { - this.updater = autoUpdater - this.updateWindow = null - this.logger = logger - this.createWindow = createWindow - } + constructor(logger, createWindow) { + this.updater = autoUpdater; + this.updateWindow = null; + this.logger = logger; + this.createWindow = createWindow; + } - checkForUpdates() { - app.showExitPrompt = true; - this.updater.checkForUpdates() - } + checkForUpdates() { + app.showExitPrompt = true; + this.updater.checkForUpdates(); + } - initUpdater() { - this.updater.logger = this.logger; - this.updater.logger.transports.file.level = "debug"; + initUpdater() { + this.updater.logger = this.logger; + this.updater.logger.transports.file.level = "debug"; - this.updater.on("checking-for-update", () => { - this.logger.info("Stereum is checking for updates."); - }); + this.updater.on("checking-for-update", () => { + this.logger.info("Stereum is checking for updates."); + }); - this.updater.on("update-available", async () => { - this.updateWindow = await this.createWindow("update") - if (this.updateWindow) - this.updateWindow.webContents.send('UpdateEvents', { message: "Update available.", type: "available" }) - this.logger.info("Update available."); - }); + this.updater.on("update-available", async () => { + this.updateWindow = await this.createWindow("update"); + if (this.updateWindow) this.updateWindow.webContents.send("UpdateEvents", { message: "Update available.", type: "available" }); + this.logger.info("Update available."); + }); - this.updater.on("update-not-available", () => { - app.showExitPrompt = false; - this.createWindow(); - this.logger.info("No updates available. Stereum is Up-to-date."); - }); + this.updater.on("update-not-available", () => { + app.showExitPrompt = false; + this.createWindow(); + this.logger.info("No updates available. Stereum is Up-to-date."); + }); - this.updater.on("download-progress", (data) => { - if (this.updateWindow) - this.updateWindow.webContents.send('UpdateEvents', { message: "Downloading update...", type: "downloading", data: { percent: data.percent, MBps: data.bytesPerSecond / 1000000 } }) - this.logger.info("Update progress", data); + this.updater.on("download-progress", (data) => { + if (this.updateWindow) + this.updateWindow.webContents.send("UpdateEvents", { + message: "Downloading update...", + type: "downloading", + data: { percent: data.percent, MBps: data.bytesPerSecond / 1000000 }, }); + this.logger.info("Update progress", data); + }); - this.updater.on("update-downloaded", async (data) => { - app.showExitPrompt = false - if (this.updateWindow) - this.updateWindow.webContents.send('UpdateEvents', { message: "Update downloaded. " + data.version, type: "downloaded" }) - this.updater.quitAndInstall() - this.logger.info("Update downloaded.", data); - }); + this.updater.on("update-downloaded", async (data) => { + app.showExitPrompt = false; + if (this.updateWindow) + this.updateWindow.webContents.send("UpdateEvents", { message: "Update downloaded. " + data.version, type: "downloaded" }); + this.updater.quitAndInstall(); + this.logger.info("Update downloaded.", data); + }); - this.updater.on("error", async (error) => { - app.showExitPrompt = false; - const allWindows = await BrowserWindow.getAllWindows(); - for (const win of allWindows) { - await win.close() - } - this.createWindow(); - this.logger.error("Error: ", error) - }); - } + this.updater.on("error", async (error) => { + app.showExitPrompt = false; + const allWindows = await BrowserWindow.getAllWindows(); + for (const win of allWindows) { + await win.close(); + } + this.createWindow(); + this.logger.error("Error: ", error); + }); + } - async runDebug() { - async function Sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); - } - this.updateWindow = await this.createWindow("update"); - await Sleep(5000) - for (let i = 0; i < 10; i++) { - this.updateWindow.webContents.send('UpdateEvents', { message: "Downloading update...", type: "downloading", data: { percent: i * 10, MBps: i * 10.11 } }) - await Sleep(1000) - } - this.updateWindow.webContents.send('UpdateEvents', { message: "Update downloaded. " + "2.0.0-rc.20", type: "downloaded" }) - await Sleep(1000) - this.updateWindow.close() + async runDebug() { + async function Sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + this.updateWindow = await this.createWindow("update"); + await Sleep(5000); + for (let i = 0; i < 10; i++) { + this.updateWindow.webContents.send("UpdateEvents", { + message: "Downloading update...", + type: "downloading", + data: { percent: i * 10, MBps: i * 10.11 }, + }); + await Sleep(1000); } -} \ No newline at end of file + this.updateWindow.webContents.send("UpdateEvents", { message: "Update downloaded. " + "2.0.0-rc.20", type: "downloaded" }); + await Sleep(1000); + this.updateWindow.close(); + } +} diff --git a/launcher/src/backend/AuthenticationService.js b/launcher/src/backend/AuthenticationService.js index 67d78ba4bb..f96e95a62d 100644 --- a/launcher/src/backend/AuthenticationService.js +++ b/launcher/src/backend/AuthenticationService.js @@ -49,16 +49,16 @@ export class AuthenticationService { outputArray.push( outputString[ - outputString.findIndex(function (item) { - return item.indexOf("https") !== -1; - }) + outputString.findIndex(function (item) { + return item.indexOf("https") !== -1; + }) ] ); outputArray.push( outputString[ - outputString.findIndex(function (item) { - return item.indexOf("secret key") !== -1; - }) + outputString.findIndex(function (item) { + return item.indexOf("secret key") !== -1; + }) ] ); win.send("2FAEvents", outputArray); @@ -96,9 +96,9 @@ export class AuthenticationService { outputArray.push( outputString[ - outputString.findIndex(function (item) { - return item.indexOf("https") !== -1; - }) + outputString.findIndex(function (item) { + return item.indexOf("https") !== -1; + }) ] ); @@ -165,7 +165,7 @@ export class AuthenticationService { async create2FAQRCode(type, name, ip, secret) { let otpauth = `otpauth://${type}/${ip}@${name}?secret=${secret}&issuer=${name}`; - const url = await QRCode.toDataURL(otpauth) + const url = await QRCode.toDataURL(otpauth); return url; } } diff --git a/launcher/src/backend/ConfigManager.js b/launcher/src/backend/ConfigManager.js index b641202d37..ce6d45adcf 100644 --- a/launcher/src/backend/ConfigManager.js +++ b/launcher/src/backend/ConfigManager.js @@ -7,12 +7,7 @@ export class ConfigManager { this.nodeConnection = nodeConnection; this.serviceManager = null; this.multiSetupPath = "/etc/stereum/multisetup.yaml"; - this.commonServices = [ - "PrometheusService", - "GrafanaService", - "PrometheusNodeExporterService", - "NotificationService", - ]; + this.commonServices = ["PrometheusService", "GrafanaService", "PrometheusNodeExporterService", "NotificationService"]; } setServiceManager(serviceManager) { this.serviceManager = serviceManager; @@ -56,9 +51,7 @@ export class ConfigManager { * @returns {Promise} Resolves with command execution result, indicating file existence. */ async checkFileExistence() { - const fileExistResult = await this.nodeConnection.sshService.exec( - `test -f ${this.multiSetupPath} && echo "exist" || echo "notExist"` - ); + const fileExistResult = await this.nodeConnection.sshService.exec(`test -f ${this.multiSetupPath} && echo "exist" || echo "notExist"`); return fileExistResult; } @@ -166,9 +159,7 @@ export class ConfigManager { } if (commonServices.length > 0) { - commonServicesObj[setupId].services = commonServicesObj[setupId].services.concat( - commonServices.map((service) => service.id) - ); + commonServicesObj[setupId].services = commonServicesObj[setupId].services.concat(commonServices.map((service) => service.id)); } return commonServicesObj; } diff --git a/launcher/src/backend/HetznerServer.js b/launcher/src/backend/HetznerServer.js index 7c914d7da3..a62f71b4d3 100755 --- a/launcher/src/backend/HetznerServer.js +++ b/launcher/src/backend/HetznerServer.js @@ -1,4 +1,6 @@ -const { utils: { generateKeyPairSync } } = require('ssh2'); +const { + utils: { generateKeyPairSync }, +} = require("ssh2"); const log = require("electron-log"); const https = require("https"); @@ -9,26 +11,28 @@ export class HetznerServer { this.serverName = null; this.serverIPv4 = null; this.serverRootPassword = null; - this.sshKeyPair = generateKeyPairSync("ed25519") + this.sshKeyPair = generateKeyPairSync("ed25519"); this.sshKeyName = null; } async Sleep(ms) { - let interval - await new Promise((resolve) => { interval = setTimeout(resolve, ms) }); + let interval; + await new Promise((resolve) => { + interval = setTimeout(resolve, ms); + }); clearInterval(interval); } async checkServerConnection(nodeConnection) { let tries = 0; - let connected = false + let connected = false; while (!connected && tries < 300) { try { - tries++ - log.info(`Trying to connect (${tries})`) - connected = await nodeConnection.sshService.checkSSHConnection(nodeConnection.nodeConnectionParams, 5000) + tries++; + log.info(`Trying to connect (${tries})`); + connected = await nodeConnection.sshService.checkSSHConnection(nodeConnection.nodeConnectionParams, 5000); } catch (err) { - log.info(err) + log.info(err); } } } @@ -71,16 +75,16 @@ export class HetznerServer { data += d; }); res.on("end", () => { - log.debug(`${options.method} ${options.path} ${res.statusCode} ${res.statusMessage}`) + log.debug(`${options.method} ${options.path} ${res.statusCode} ${res.statusMessage}`); if (res.statusCode >= 300) { - log.error(data) + log.error(data); } resolve(data); }); }); req.on("error", (err) => { - log.info(`${method} ${path} ${query} ${body}`) + log.info(`${method} ${path} ${query} ${body}`); log.error(err); reject(err); }); @@ -137,7 +141,7 @@ export class HetznerServer { * Destroys Server via API call */ async destroy() { - log.info("Destroying Server with ID " + this.serverID + " ...") + log.info("Destroying Server with ID " + this.serverID + " ..."); await this.makeRequest("DELETE", `/v1/servers/${this.serverID}`); @@ -177,7 +181,7 @@ export class HetznerServer { ip: ip, network: networkID, }; - await this.makeRequest("POST", `/v1/servers/${this.serverID}/actions/attach_to_network`, "", JSON.stringify(settings)) + await this.makeRequest("POST", `/v1/servers/${this.serverID}/actions/attach_to_network`, "", JSON.stringify(settings)); } async getSSHKeyByName(name) { @@ -203,16 +207,18 @@ export class HetznerServer { const existing = response.ssh_keys.find((key) => key.name === name); if (existing && existing.id) { await this.deleteSSHKey(existing.id); - log.debug("deleted existing ssh key with name " + name + " and id " + existing.id) + log.debug("deleted existing ssh key with name " + name + " and id " + existing.id); } - return JSON.parse(await this.makeRequest("POST", "/v1/ssh_keys", "", JSON.stringify({ name: name, public_key: this.sshKeyPair.public }))); + return JSON.parse( + await this.makeRequest("POST", "/v1/ssh_keys", "", JSON.stringify({ name: name, public_key: this.sshKeyPair.public })) + ); } async finishTestGracefully(nodeConnection) { - clearInterval(nodeConnection.sshService.checkPoolPolling) - await this.Sleep(10000) + clearInterval(nodeConnection.sshService.checkPoolPolling); + await this.Sleep(10000); await nodeConnection.sshService.disconnect(); - await this.deleteSSHKey() + await this.deleteSSHKey(); await this.destroy(); } } diff --git a/launcher/src/backend/Monitoring.js b/launcher/src/backend/Monitoring.js index 93f99de8b0..a9a627ff1b 100755 --- a/launcher/src/backend/Monitoring.js +++ b/launcher/src/backend/Monitoring.js @@ -248,13 +248,7 @@ export class Monitoring { if (await this.checkStereumInstallation()) { var serviceConfigs = await this.serviceManagerProm.readServiceConfigurations(); const serviceStates = await this.nodeConnectionProm.listServices(); - if ( - serviceConfigs && - Array.isArray(serviceConfigs) && - serviceConfigs.length > 0 && - serviceStates && - Array.isArray(serviceStates) - ) { + if (serviceConfigs && Array.isArray(serviceConfigs) && serviceConfigs.length > 0 && serviceStates && Array.isArray(serviceStates)) { serviceConfigs = args.length < 1 ? serviceConfigs : serviceConfigs.filter((s) => args.includes(s.service)); serviceConfigs = serviceConfigs .map((config) => { @@ -663,8 +657,7 @@ export class Monitoring { let requestdata = d ? `-d '${d}'` : ""; // Build curl command - const cmd = - `curl -s --location --request ${method} -w "\\n%{http_code}" '${url}' ${requestheaders} ${requestdata}`.trim(); + const cmd = `curl -s --location --request ${method} -w "\\n%{http_code}" '${url}' ${requestheaders} ${requestdata}`.trim(); // Execute the CURL command on the node and return the result let result = null; @@ -804,8 +797,7 @@ export class Monitoring { let requestdata = d ? `-d '${d}'` : ""; // Build curl command - const cmd = - `curl -s --location --request ${method} -w "\\n%{http_code}" '${url}' ${requestheaders} ${requestdata}`.trim(); + const cmd = `curl -s --location --request ${method} -w "\\n%{http_code}" '${url}' ${requestheaders} ${requestdata}`.trim(); // Execute the CURL command on the node and return the result let result = null; @@ -1083,8 +1075,7 @@ export class Monitoring { // Respond success return { code: 0, - info: - "success: rpc data" + (addinfo ? addinfo : " for all running execution clients") + " successfully retrieved", + info: "success: rpc data" + (addinfo ? addinfo : " for all running execution clients") + " successfully retrieved", data: data, }; } @@ -1171,11 +1162,7 @@ export class Monitoring { // Query Prometehus for all possible labels const prometheus_result = await this.queryPrometheus('{__name__=~"' + serviceLabels.join("|") + '"}'); - if ( - typeof prometheus_result !== "object" || - !prometheus_result.hasOwnProperty("status") || - prometheus_result.status != "success" - ) { + if (typeof prometheus_result !== "object" || !prometheus_result.hasOwnProperty("status") || prometheus_result.status != "success") { return { code: 113, info: "error: prometheus query for syncstatus failed", @@ -1224,9 +1211,7 @@ export class Monitoring { let head_block_number = 0; if (typeof ecBlockNumberByRPC == "object") { last_known_head_block_number = await this.getLastKnownHeadBlock(network); - last_known_head_block_number = !this.is_numeric(last_known_head_block_number) - ? 0 - : last_known_head_block_number; + last_known_head_block_number = !this.is_numeric(last_known_head_block_number) ? 0 : last_known_head_block_number; head_block_number = await this.getExecutionHeadBlockFromBeaconApi(consensus.config.serviceID); await this.setLastKnownHeadBlock(head_block_number, network); // does update only if head_block_number is a number and higher if (!this.is_numeric(head_block_number)) { @@ -1240,9 +1225,7 @@ export class Monitoring { let labels = services[clientType][clt.service]; let xx = prometheus_result.data.result.filter( (s) => - labels.includes(s.metric.__name__) && - s.metric.instance.includes(clt.config.instanceID) && - s.metric.job == jobs[clt.service] + labels.includes(s.metric.__name__) && s.metric.instance.includes(clt.config.instanceID) && s.metric.job == jobs[clt.service] ); let frstVal = 0, scndVal = 0; @@ -1269,9 +1252,7 @@ export class Monitoring { const ecbfilt = ecBlockNumberByRPC.data.filter((s) => s.instance_id == clt.config.instanceID).pop(); chain_head_block = ecbfilt.query_result.data.api_reponse; chain_head_block = - typeof chain_head_block === "string" && chain_head_block.startsWith("0x") - ? parseInt(chain_head_block, 16) - : 0; + typeof chain_head_block === "string" && chain_head_block.startsWith("0x") ? parseInt(chain_head_block, 16) : 0; } catch (e) {} let stay_on_hold_till_first_block = false; // true = enabled | false = disabled if (stay_on_hold_till_first_block && !chain_head_block) { @@ -1377,11 +1358,7 @@ export class Monitoring { // Query Prometehus for all possible labels const prometheus_result = await this.queryPrometheus('{__name__=~"' + serviceLabels.join("|") + '"}'); - if ( - typeof prometheus_result !== "object" || - !prometheus_result.hasOwnProperty("status") || - prometheus_result.status != "success" - ) { + if (typeof prometheus_result !== "object" || !prometheus_result.hasOwnProperty("status") || prometheus_result.status != "success") { return { code: 223, info: "error: prometheus query for p2pstatus failed", @@ -1599,9 +1576,7 @@ export class Monitoring { details[clientType]["numPeer"] > details[clientType]["maxPeer"] ? details[clientType]["maxPeer"] : details[clientType]["numPeer"]; - details[clientType]["valPeer"] = Math.round( - (details[clientType]["numPeer"] / details[clientType]["maxPeer"]) * 100 - ); + details[clientType]["valPeer"] = Math.round((details[clientType]["numPeer"] / details[clientType]["maxPeer"]) * 100); details[clientType]["valPeer"] = details[clientType]["valPeer"] > 100 ? 100 : details[clientType]["valPeer"]; // Summarize totals @@ -1654,10 +1629,7 @@ export class Monitoring { // By default return cached data (if available) if (!live) { - if ( - !this.globalMonitoringCache.hasOwnProperty("storagestatus") || - !this.globalMonitoringCache.storagestatus.hasOwnProperty("data") - ) { + if (!this.globalMonitoringCache.hasOwnProperty("storagestatus") || !this.globalMonitoringCache.storagestatus.hasOwnProperty("data")) { return { code: 330, info: "error: storagestatus not available (waiting for updated cache)", @@ -1789,8 +1761,7 @@ export class Monitoring { const rewardsPerValidator = attestationResult.data.api_reponse.data.total_rewards.map((data) => { return { ...data, - total_rewards: - parseInt(data.head) + parseInt(data.source) + parseInt(data.target) + parseInt(data.inactivity), + total_rewards: parseInt(data.head) + parseInt(data.source) + parseInt(data.target) + parseInt(data.inactivity), }; }); @@ -1839,12 +1810,7 @@ export class Monitoring { const baseURL = `http://127.0.0.1:${beaconResult.data.port}`; // Get attestation rewards for given validators - const blockResult = await this.queryBeaconApi( - baseURL, - "/eth/v1/beacon/rewards/sync_committee/" + slot, - validators, - "POST" - ); + const blockResult = await this.queryBeaconApi(baseURL, "/eth/v1/beacon/rewards/sync_committee/" + slot, validators, "POST"); return blockResult.data.api_httpcode == 200 ? blockResult.data.api_reponse.data : []; } catch (error) { log.error("Getting Block Rewards Failed:\n" + error); @@ -2620,11 +2586,7 @@ export class Monitoring { } // Check and format addr - const addr_type = Array.isArray(addr) - ? "arr" - : typeof addr === "string" && ["public", "local"].includes(addr) - ? "str" - : "invalid"; + const addr_type = Array.isArray(addr) ? "arr" : typeof addr === "string" && ["public", "local"].includes(addr) ? "str" : "invalid"; addr = addr_type == "str" ? addr.toLowerCase().trim() : addr; if (addr_type == "invalid") { return { @@ -2644,11 +2606,7 @@ export class Monitoring { if (ports.length < 1) continue; for (let n = 0; n < ports.length; n++) { if (addr == "public" && addresses.some((w) => ports[n].destinationIp.toLowerCase().includes(w))) continue; - if ( - (addr_type == "arr" || addr == "local") && - !addresses.some((w) => ports[n].destinationIp.toLowerCase().includes(w)) - ) - continue; + if ((addr_type == "arr" || addr == "local") && !addresses.some((w) => ports[n].destinationIp.toLowerCase().includes(w))) continue; data.push({ name: svc.service.replace(/Beacon|Service/gi, "").toUpperCase(), port: ports[n].destinationPort, @@ -2666,8 +2624,7 @@ export class Monitoring { // ); // Return success - const addinfo = - addr_type === "str" ? "that are " + addr + "ly available" : "that are available thru ip " + addr.join(" or "); + const addinfo = addr_type === "str" ? "that are " + addr + "ly available" : "that are available thru ip " + addr.join(" or "); return { code: 0, info: "success: open ports " + addinfo + " retrieved", @@ -2711,8 +2668,7 @@ export class Monitoring { const easyInfos = []; for (let i = 0; i < serviceInfos.length; i++) { const hashDependencies = - serviceInfos[i].config.dependencies.consensusClients.length || - serviceInfos[i].config.dependencies.executionClients.length + serviceInfos[i].config.dependencies.consensusClients.length || serviceInfos[i].config.dependencies.executionClients.length ? "yes" : "no"; easyInfos.push({ @@ -2996,23 +2952,11 @@ rm -rf diskoutput const { current_epoch, current_slot } = await this.getCurrentEpochandSlot(); - let proposerDutiesRes = await this.queryBeaconApi( - baseURL, - "/eth/v1/validator/duties/proposer/" + current_epoch, - [], - "GET" - ); - let syncDutiesRes = await this.queryBeaconApi( - baseURL, - "/eth/v1/validator/duties/sync/" + current_epoch, - validatorIndices, - "POST" - ); + let proposerDutiesRes = await this.queryBeaconApi(baseURL, "/eth/v1/validator/duties/proposer/" + current_epoch, [], "GET"); + let syncDutiesRes = await this.queryBeaconApi(baseURL, "/eth/v1/validator/duties/sync/" + current_epoch, validatorIndices, "POST"); return { - proposerDuties: proposerDutiesRes.data.api_reponse.data.filter((d) => - validatorIndices.some((i) => i === d.validator_index) - ), // filter out duties for validators that are not in the validatorIndices (imported vals) array + proposerDuties: proposerDutiesRes.data.api_reponse.data.filter((d) => validatorIndices.some((i) => i === d.validator_index)), // filter out duties for validators that are not in the validatorIndices (imported vals) array syncDuties: syncDutiesRes.data.api_reponse.data, currentEpoch: current_epoch, currentSlot: current_slot, @@ -3052,9 +2996,7 @@ rm -rf diskoutput //check response validatorNotFound = - beaconAPIRunCmd.rc != 0 || - beaconAPIRunCmd.stderr || - JSON.parse(beaconAPIRunCmd.stdout).hasOwnProperty("message"); + beaconAPIRunCmd.rc != 0 || beaconAPIRunCmd.stderr || JSON.parse(beaconAPIRunCmd.stdout).hasOwnProperty("message"); if (!validatorNotFound) data = data.concat(JSON.parse(beaconAPIRunCmd.stdout).data); //merge all gathered stats in one array } const beaconAPICmdLastEpoch = `curl -s -X GET 'http://localhost:${beaconAPIPort}/eth/v1/beacon/states/head/finality_checkpoints' -H 'accept: application/json'`; @@ -3112,9 +3054,7 @@ rm -rf diskoutput let notFound = ":404"; let beaconAPISlotRunCmd = await this.nodeConnection.sshService.exec(`${APIBegin}headers/head${cmdEnd}`); - let beaconAPIEpochRunCmd = await this.nodeConnection.sshService.exec( - `${APIBegin}states/head/finality_checkpoints${cmdEnd}` - ); + let beaconAPIEpochRunCmd = await this.nodeConnection.sshService.exec(`${APIBegin}states/head/finality_checkpoints${cmdEnd}`); let currentSlot = parseInt(JSON.parse(beaconAPISlotRunCmd.stdout).data.header.message.slot); let currentEpoch = Math.floor(currentSlot / epochLength); @@ -3151,8 +3091,7 @@ rm -rf diskoutput }; for (const slots in firstSlots) { - let slotsNumberInEpoch = - `${slots}` === "firstSlotInCurrentEpoch" ? (currentSlot % epochLength) + 1 : epochLength; + let slotsNumberInEpoch = `${slots}` === "firstSlotInCurrentEpoch" ? (currentSlot % epochLength) + 1 : epochLength; for (let i = 0; i < slotsNumberInEpoch; i++) { let beaconAPISlotStatusCmd = @@ -3355,8 +3294,7 @@ rm -rf diskoutput } const queries = { app_monitoring_readyz: "max((app_monitoring_readyz)) by (cluster_name, cluster_hash, cluster_peer)", - cluster_missed_attestations: - "max(increase(core_tracker_failed_duties_total[10m])) by (cluster_hash, cluster_name)", + cluster_missed_attestations: "max(increase(core_tracker_failed_duties_total[10m])) by (cluster_hash, cluster_name)", cluster_failure_rate: "floor(100 * (max(increase(core_tracker_success_duties_total[15m])) by (cluster_hash, cluster_name) / max(increase(core_tracker_expect_duties_total[15m])) by (cluster_hash, cluster_name)))", percentage_failed_sync_message_duty: diff --git a/launcher/src/backend/NodeConnection.js b/launcher/src/backend/NodeConnection.js index a5565984be..8193ea9506 100755 --- a/launcher/src/backend/NodeConnection.js +++ b/launcher/src/backend/NodeConnection.js @@ -385,9 +385,7 @@ export class NodeConnection { } if (SSHService.checkExecError(statusResult)) { - throw new Error( - "Failed reading status of ref '" + playbookRunRef + "': " + SSHService.extractExecError(statusResult) - ); + throw new Error("Failed reading status of ref '" + playbookRunRef + "': " + SSHService.extractExecError(statusResult)); } return statusResult.stdout; @@ -426,9 +424,7 @@ export class NodeConnection { } if (SSHService.checkExecError(serviceConfig)) { - throw new Error( - "Failed reading service configuration " + serviceId + ": " + SSHService.extractExecError(serviceConfig) - ); + throw new Error("Failed reading service configuration " + serviceId + ": " + SSHService.extractExecError(serviceConfig)); } return YAML.parse(serviceConfig.stdout); @@ -576,9 +572,7 @@ export class NodeConnection { async getSSVLastKnownOperatorIdFilePath(serviceID, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const getSSVNetworkConfig = getSsvNetworkCfg - ? getSsvNetworkCfg - : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); + const getSSVNetworkConfig = getSsvNetworkCfg ? getSsvNetworkCfg : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); const ssvNetworkConfigDir = getSSVNetworkConfig.ssvNetworkConfigDir; return ssvNetworkConfigDir + "/last_known_operator_id"; } catch (err) { @@ -599,27 +593,16 @@ export class NodeConnection { try { try { if (!force) { - const existing = await this.getSSVLastKnownOperatorId( - serviceID, - return_details, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const existing = await this.getSSVLastKnownOperatorId(serviceID, return_details, getSsvServiceCfg, getSsvNetworkCfg); const existingLastKnownOperatorId = return_details ? existing.lastKnownOperatorIdFileData : existing; if (existingLastKnownOperatorId == strOperatorId.trim()) { return existing; } } } catch (err) {} - const lastKnownOperatorIdFilePath = await this.getSSVLastKnownOperatorIdFilePath( - serviceID, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const lastKnownOperatorIdFilePath = await this.getSSVLastKnownOperatorIdFilePath(serviceID, getSsvServiceCfg, getSsvNetworkCfg); const lastKnownOperatorIdFileData = strOperatorId.trim(); - const result = await this.sshService.exec( - `echo -n "${lastKnownOperatorIdFileData}" > "${lastKnownOperatorIdFilePath}"` - ); + const result = await this.sshService.exec(`echo -n "${lastKnownOperatorIdFileData}" > "${lastKnownOperatorIdFilePath}"`); if (SSHService.checkExecError(result, true)) { throw new Error(SSHService.extractExecError(result)); } @@ -636,11 +619,7 @@ export class NodeConnection { async getSSVLastKnownOperatorId(serviceID, return_details = false, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const lastKnownOperatorIdFilePath = await this.getSSVLastKnownOperatorIdFilePath( - serviceID, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const lastKnownOperatorIdFilePath = await this.getSSVLastKnownOperatorIdFilePath(serviceID, getSsvServiceCfg, getSsvNetworkCfg); let lastKnownOperatorIdFileContent = ""; if (lastKnownOperatorIdFilePath) { let lastKnownOperatorIdFileRequest = await this.sshService.exec( @@ -665,9 +644,7 @@ export class NodeConnection { async getSSVLastBackedPublicKeyFilePath(serviceID, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const getSSVNetworkConfig = getSsvNetworkCfg - ? getSsvNetworkCfg - : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); + const getSSVNetworkConfig = getSsvNetworkCfg ? getSsvNetworkCfg : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); const ssvNetworkConfigDir = getSSVNetworkConfig.ssvNetworkConfigDir; return ssvNetworkConfigDir + "/last_backed_public_key"; } catch (err) { @@ -676,23 +653,11 @@ export class NodeConnection { } } - async setSSVLastBackedPublicKey( - serviceID, - strPublicKey, - return_details = false, - getSsvServiceCfg = null, - getSsvNetworkCfg = null - ) { + async setSSVLastBackedPublicKey(serviceID, strPublicKey, return_details = false, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const lastBackedPublicKeyFilePath = await this.getSSVLastBackedPublicKeyFilePath( - serviceID, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const lastBackedPublicKeyFilePath = await this.getSSVLastBackedPublicKeyFilePath(serviceID, getSsvServiceCfg, getSsvNetworkCfg); const lastBackedPublicKeyFileData = strPublicKey.trim(); - const result = await this.sshService.exec( - `echo -n "${lastBackedPublicKeyFileData}" > "${lastBackedPublicKeyFilePath}"` - ); + const result = await this.sshService.exec(`echo -n "${lastBackedPublicKeyFileData}" > "${lastBackedPublicKeyFilePath}"`); if (SSHService.checkExecError(result, true)) { throw new Error(SSHService.extractExecError(result)); } @@ -709,11 +674,7 @@ export class NodeConnection { async getSSVLastBackedPublicKey(serviceID, return_details = false, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const lastBackedPublicKeyFilePath = await this.getSSVLastBackedPublicKeyFilePath( - serviceID, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const lastBackedPublicKeyFilePath = await this.getSSVLastBackedPublicKeyFilePath(serviceID, getSsvServiceCfg, getSsvNetworkCfg); let lastBackedPublicKeyFileContent = ""; if (lastBackedPublicKeyFilePath) { let lastBackedPublicKeyFileRequest = await this.sshService.exec( @@ -812,9 +773,7 @@ export class NodeConnection { throw new Error(SSHService.extractExecError(service_config_read)); } const escapedServiceConfigFile = StringUtils.escapeStringForShell( - service_config_read.stdout - .replace(/^(ssv_pk|ssv_sk|# BEGIN ANSIBLE MANAGED BLOCK|# END ANSIBLE MANAGED BLOCK).*/gm, "") - .trim() + service_config_read.stdout.replace(/^(ssv_pk|ssv_sk|# BEGIN ANSIBLE MANAGED BLOCK|# END ANSIBLE MANAGED BLOCK).*/gm, "").trim() ); const service_config_write = await this.sshService.exec(` mkdir -p ${service_config_dir} && @@ -978,9 +937,7 @@ export class NodeConnection { // Check (unencrypted) SSV secret key (private_key) if (!private_key) { - throw new Error( - "Unencrypted SSV secret key (private key) is invalid (neither given as argument nor found on the server)" - ); + throw new Error("Unencrypted SSV secret key (private key) is invalid (neither given as argument nor found on the server)"); } if (!StringUtils.isBase64(private_key)) { throw new Error("Unencrypted SSV secret key (private key) is invalid (not base 64 encoded)"); @@ -1059,9 +1016,7 @@ export class NodeConnection { } const service_config_content = service_config_read.stdout; const escapedServiceConfigFile = StringUtils.escapeStringForShell( - service_config_content - .replace(/^(ssv_pk|ssv_sk|# BEGIN ANSIBLE MANAGED BLOCK|# END ANSIBLE MANAGED BLOCK).*/gm, "") - .trim() + service_config_content.replace(/^(ssv_pk|ssv_sk|# BEGIN ANSIBLE MANAGED BLOCK|# END ANSIBLE MANAGED BLOCK).*/gm, "").trim() ); const service_config_write = await this.sshService.exec( `mkdir -p ${service_config_dir} && echo ${escapedServiceConfigFile} > ${service_config_file} && @@ -1171,9 +1126,7 @@ export class NodeConnection { throw new Error(SSHService.extractExecError(service_config_read)); } const escapedServiceConfigFile = StringUtils.escapeStringForShell( - service_config_read.stdout - .replace(/^(ssv_pk|ssv_sk|# BEGIN ANSIBLE MANAGED BLOCK|# END ANSIBLE MANAGED BLOCK).*/gm, "") - .trim() + service_config_read.stdout.replace(/^(ssv_pk|ssv_sk|# BEGIN ANSIBLE MANAGED BLOCK|# END ANSIBLE MANAGED BLOCK).*/gm, "").trim() ); const service_config_write = await this.sshService.exec(` mkdir -p ${service_config_dir} && @@ -1252,9 +1205,7 @@ export class NodeConnection { async getSSVLastKnownPublicKeyFilePath(serviceID, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const getSSVNetworkConfig = getSsvNetworkCfg - ? getSsvNetworkCfg - : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); + const getSSVNetworkConfig = getSsvNetworkCfg ? getSsvNetworkCfg : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); const ssvNetworkConfigDir = getSSVNetworkConfig.ssvNetworkConfigDir; return ssvNetworkConfigDir + "/last_known_public_key"; } catch (err) { @@ -1265,15 +1216,9 @@ export class NodeConnection { async writeSSVLastKnownPublicKeyFile(serviceID, strPublicKey, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const lastKnownPublicKeyFilePath = await this.getSSVLastKnownPublicKeyFilePath( - serviceID, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const lastKnownPublicKeyFilePath = await this.getSSVLastKnownPublicKeyFilePath(serviceID, getSsvServiceCfg, getSsvNetworkCfg); const lastKnownPublicKeyFileData = strPublicKey.trim(); - const result = await this.sshService.exec( - `echo -n "${lastKnownPublicKeyFileData}" > "${lastKnownPublicKeyFilePath}"` - ); + const result = await this.sshService.exec(`echo -n "${lastKnownPublicKeyFileData}" > "${lastKnownPublicKeyFilePath}"`); if (SSHService.checkExecError(result, true)) { throw new Error(SSHService.extractExecError(result)); } @@ -1289,11 +1234,7 @@ export class NodeConnection { async getSSVLastKnownPublicKeyFile(serviceID, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const lastKnownPublicKeyFilePath = await this.getSSVLastKnownPublicKeyFilePath( - serviceID, - getSsvServiceCfg, - getSsvNetworkCfg - ); + const lastKnownPublicKeyFilePath = await this.getSSVLastKnownPublicKeyFilePath(serviceID, getSsvServiceCfg, getSsvNetworkCfg); let lastKnownPublicKeyFileContent = ""; if (lastKnownPublicKeyFilePath) { let lastKnownPublicKeyFileRequest = await this.sshService.exec( @@ -1317,9 +1258,7 @@ export class NodeConnection { async getSSVTotalConfig(serviceID, getSsvServiceCfg = null, getSsvNetworkCfg = null) { try { - const getSsvNetworkConfig = getSsvNetworkCfg - ? getSsvNetworkCfg - : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); + const getSsvNetworkConfig = getSsvNetworkCfg ? getSsvNetworkCfg : await this.getSSVNetworkConfig(serviceID, getSsvServiceCfg); const getSsvServiceConfig = getSsvNetworkConfig.getSsvServiceConfig; const ssvServiceConfig = getSsvNetworkConfig.ssvServiceConfig; const ssvServiceConfigDir = getSsvNetworkConfig.ssvServiceConfigDir; @@ -1344,9 +1283,7 @@ export class NodeConnection { } else if (regexS.test(keyStorePasswordFile)) { keyStorePasswordFile = ssvSecretsDir + "/" + keyStorePasswordFile.replace(regexS, ""); // password file found in secrets dir } - let keyStorePrivateKeyFile = ssvNetworkConfig?.KeyStore?.PrivateKeyFile - ? ssvNetworkConfig.KeyStore.PrivateKeyFile - : ""; + let keyStorePrivateKeyFile = ssvNetworkConfig?.KeyStore?.PrivateKeyFile ? ssvNetworkConfig.KeyStore.PrivateKeyFile : ""; if (regexC.test(keyStorePrivateKeyFile)) { keyStorePrivateKeyFile = ssvNetworkConfigDir + "/" + keyStorePrivateKeyFile.replace(regexC, ""); // keystore file found in config dir } else if (regexS.test(keyStorePrivateKeyFile)) { @@ -1359,10 +1296,7 @@ export class NodeConnection { `if [ -f "${keyStorePasswordFile}" ]; then cat "${keyStorePasswordFile}"; else echo ""; fi` ); if (SSHService.checkExecError(keyStorePasswordFileRequest, true)) { - log.error( - "Can't read SSV keystore password file content from service " + serviceID, - keyStorePasswordFileRequest.stderr - ); + log.error("Can't read SSV keystore password file content from service " + serviceID, keyStorePasswordFileRequest.stderr); } else { keyStorePasswordFileContent = keyStorePasswordFileRequest.stdout; } @@ -1374,10 +1308,7 @@ export class NodeConnection { `if [ -f "${keyStorePrivateKeyFile}" ]; then cat "${keyStorePrivateKeyFile}"; else echo ""; fi` ); if (SSHService.checkExecError(keyStorePrivateKeyFileRequest, true)) { - log.error( - "Can't read SSV keystore private key file content from service " + serviceID, - keyStorePrivateKeyFileRequest.stderr - ); + log.error("Can't read SSV keystore private key file content from service " + serviceID, keyStorePrivateKeyFileRequest.stderr); } else { keyStorePrivateKeyFileContent = keyStorePrivateKeyFileRequest.stdout; } @@ -1386,34 +1317,20 @@ export class NodeConnection { let operatorPrivateKey = ssvNetworkConfig?.OperatorPrivateKey ? ssvNetworkConfig.OperatorPrivateKey : ""; // Last known public key that was generated or imported by the end-user via ssv modal generate/import buttons - const getSSVLastKnownPublicKeyFile = await this.getSSVLastKnownPublicKeyFile( - serviceID, - getSsvServiceConfig, - getSsvNetworkConfig - ); + const getSSVLastKnownPublicKeyFile = await this.getSSVLastKnownPublicKeyFile(serviceID, getSsvServiceConfig, getSsvNetworkConfig); const lastKnownPublicKeyFilePath = getSSVLastKnownPublicKeyFile.lastKnownPublicKeyFilePath; const lastKnownPublicKeyFileData = getSSVLastKnownPublicKeyFile.lastKnownPublicKeyFileData; // Last backed public key (empty as long as user did not do any backup) let lastBackedPublicKey = ""; try { - lastBackedPublicKey = await this.getSSVLastBackedPublicKey( - serviceID, - false, - getSsvServiceConfig, - getSsvNetworkConfig - ); + lastBackedPublicKey = await this.getSSVLastBackedPublicKey(serviceID, false, getSsvServiceConfig, getSsvNetworkConfig); } catch (err) {} // Last known operator id that was responded by SSV API (empty as long as operator is not registered or SSV-API is unreachable) let lastKnownOperatorId = ""; try { - lastKnownOperatorId = await this.getSSVLastKnownOperatorId( - serviceID, - false, - getSsvServiceConfig, - getSsvNetworkConfig - ); + lastKnownOperatorId = await this.getSSVLastKnownOperatorId(serviceID, false, getSsvServiceConfig, getSsvNetworkConfig); } catch (err) {} return { @@ -1458,9 +1375,7 @@ export class NodeConnection { let SSVNetworkConfig; try { const service = await this.readServiceConfiguration(serviceID); - let configPath = ServiceVolume.buildByConfig( - service.volumes.find((v) => v.split(":").slice(-1) == "/data") - ).destinationPath; + let configPath = ServiceVolume.buildByConfig(service.volumes.find((v) => v.split(":").slice(-1) == "/data")).destinationPath; if (configPath.endsWith("/")) configPath = configPath.slice(0, -1, ""); //if path ends with '/' remove it SSVNetworkConfig = await this.sshService.exec(`cat ${configPath}/config.yaml`); @@ -1482,9 +1397,7 @@ export class NodeConnection { this.taskManager.tasks.push({ name: "write SSV config", otherRunRef: ref }); const service = await this.readServiceConfiguration(serviceID); try { - let configPath = ServiceVolume.buildByConfig( - service.volumes.find((v) => v.split(":").slice(-1) == "/data") - ).destinationPath; + let configPath = ServiceVolume.buildByConfig(service.volumes.find((v) => v.split(":").slice(-1) == "/data")).destinationPath; if (configPath.endsWith("/")) configPath = configPath.slice(0, -1, ""); //if path ends with '/' remove it configStatus = await this.sshService.exec( "echo -e " + StringUtils.escapeStringForShell(config.trim()) + ` > ${configPath}/config.yaml` @@ -1535,9 +1448,7 @@ export class NodeConnection { async getSSVDKGConfig(serviceID, getSsvDkgServiceCfg = null) { try { - const getSsvDkgServiceConfig = getSsvDkgServiceCfg - ? getSsvDkgServiceCfg - : await this.getSSVDKGServiceConfig(serviceID); + const getSsvDkgServiceConfig = getSsvDkgServiceCfg ? getSsvDkgServiceCfg : await this.getSSVDKGServiceConfig(serviceID); const ssvDkgServiceConfig = getSsvDkgServiceConfig.ssvDkgServiceConfig; const ssvDkgServiceConfigDir = getSsvDkgServiceConfig.ssvDkgServiceConfigDir; let ssvDkgConfigDir = "."; @@ -1602,10 +1513,7 @@ export class NodeConnection { `if [ -f "${keyStorePasswordFile}" ]; then cat "${keyStorePasswordFile}"; else echo ""; fi` ); if (SSHService.checkExecError(keyStorePasswordFileRequest, true)) { - log.error( - "Can't read SSVDKG keystore password file content from service " + serviceID, - keyStorePasswordFileRequest.stderr - ); + log.error("Can't read SSVDKG keystore password file content from service " + serviceID, keyStorePasswordFileRequest.stderr); } else { keyStorePasswordFileContent = keyStorePasswordFileRequest.stdout; } @@ -1616,10 +1524,7 @@ export class NodeConnection { `if [ -f "${keyStorePrivateKeyFile}" ]; then cat "${keyStorePrivateKeyFile}"; else echo ""; fi` ); if (SSHService.checkExecError(keyStorePrivateKeyFileRequest, true)) { - log.error( - "Can't read SSVDKG keystore private key file content from service " + serviceID, - keyStorePrivateKeyFileRequest.stderr - ); + log.error("Can't read SSVDKG keystore private key file content from service " + serviceID, keyStorePrivateKeyFileRequest.stderr); } else { keyStorePrivateKeyFileContent = keyStorePrivateKeyFileRequest.stdout; } @@ -1657,9 +1562,7 @@ export class NodeConnection { let SSVDKGConfig; try { const service = await this.readServiceConfiguration(serviceID); - let configPath = ServiceVolume.buildByConfig( - service.volumes.find((v) => v.split(":").slice(-1) == "/data") - ).destinationPath; + let configPath = ServiceVolume.buildByConfig(service.volumes.find((v) => v.split(":").slice(-1) == "/data")).destinationPath; if (configPath.endsWith("/")) configPath = configPath.slice(0, -1, ""); //if path ends with '/' remove it SSVDKGConfig = await this.sshService.exec(`cat ${configPath}/config.yaml`); @@ -1681,9 +1584,7 @@ export class NodeConnection { this.taskManager.tasks.push({ name: "write SSVDKG config", otherRunRef: ref }); const service = await this.readServiceConfiguration(serviceID); try { - let configPath = ServiceVolume.buildByConfig( - service.volumes.find((v) => v.split(":").slice(-1) == "/data") - ).destinationPath; + let configPath = ServiceVolume.buildByConfig(service.volumes.find((v) => v.split(":").slice(-1) == "/data")).destinationPath; if (configPath.endsWith("/")) configPath = configPath.slice(0, -1, ""); //if path ends with '/' remove it configStatus = await this.sshService.exec( "echo -e " + StringUtils.escapeStringForShell(config.trim()) + ` > ${configPath}/config.yaml` @@ -1735,9 +1636,7 @@ export class NodeConnection { } if (SSHService.checkExecError(prometheusConfig)) { - throw new Error( - "Failed reading Prometheus config " + serviceID + ": " + SSHService.extractExecError(prometheusConfig) - ); + throw new Error("Failed reading Prometheus config " + serviceID + ": " + SSHService.extractExecError(prometheusConfig)); } return prometheusConfig.stdout; @@ -1799,11 +1698,7 @@ export class NodeConnection { throw new Error("Config is not in the right format!"); } configStatus = await this.sshService.exec( - "echo -e " + - StringUtils.escapeStringForShell(service.data.trim()) + - " > /etc/stereum/services/" + - service.id + - ".yaml" + "echo -e " + StringUtils.escapeStringForShell(service.data.trim()) + " > /etc/stereum/services/" + service.id + ".yaml" ); } catch (err) { this.taskManager.otherSubTasks.push({ @@ -1824,9 +1719,7 @@ export class NodeConnection { status: false, }); this.taskManager.finishedOtherTasks.push({ otherRunRef: ref }); - throw new Error( - "Failed writing service configuration " + service.id + ": " + SSHService.extractExecError(configStatus) - ); + throw new Error("Failed writing service configuration " + service.id + ": " + SSHService.extractExecError(configStatus)); } this.taskManager.otherSubTasks.push({ name: "write " + service.service + " config", @@ -1874,12 +1767,7 @@ export class NodeConnection { status: false, }); this.taskManager.finishedOtherTasks.push({ otherRunRef: ref }); - throw new Error( - "Failed writing service configuration " + - serviceConfiguration.id + - ": " + - SSHService.extractExecError(configStatus) - ); + throw new Error("Failed writing service configuration " + serviceConfiguration.id + ": " + SSHService.extractExecError(configStatus)); } this.taskManager.otherSubTasks.push({ name: "write " + serviceConfiguration.service + " config", @@ -1929,9 +1817,7 @@ export class NodeConnection { } if (SSHService.checkExecError(serviceJson)) { - throw new Error( - "Failed getting service details of '" + serviceId + "': " + SSHService.extractExecError(serviceJson) - ); + throw new Error("Failed getting service details of '" + serviceId + "': " + SSHService.extractExecError(serviceJson)); } return JSON.parse(serviceJson.stdout); @@ -2115,9 +2001,7 @@ export class NodeConnection { async getCurrentStereumVersion() { let response; try { - response = await this.sshService.exec( - `cd ${this.settings.stereum.settings.controls_install_path}/ansible && git rev-parse HEAD` - ); + response = await this.sshService.exec(`cd ${this.settings.stereum.settings.controls_install_path}/ansible && git rev-parse HEAD`); } catch (err) { log.error("Couldn't get Stereum Version:", err); throw new Error("Couldn't get Stereum Version:\n" + err); @@ -2136,9 +2020,7 @@ export class NodeConnection { async getLargestVolumePath() { try { - const dfOutput = await this.sshService.exec( - "df | grep -wv /var/lib/docker | tail -n +2 | sort -k 4 -rn | head -n 1" - ); + const dfOutput = await this.sshService.exec("df | grep -wv /var/lib/docker | tail -n +2 | sort -k 4 -rn | head -n 1"); if (SSHService.checkExecError(dfOutput)) { throw new Error("Failed reading df command: " + SSHService.extractExecError(dfOutput)); @@ -2432,16 +2314,13 @@ export class NodeConnection { // Calculate the timestamp for the 'since' days ago const sinceDate = new Date(Date.now() - 1000 * 60 * 60 * 24 * since).toISOString(); // Calculate the timestamp for the 'until' days ago - const untilDate = - until === 0 ? new Date().toISOString() : new Date(Date.now() - 1000 * 60 * 60 * 24 * until).toISOString(); + const untilDate = until === 0 ? new Date().toISOString() : new Date(Date.now() - 1000 * 60 * 60 * 24 * until).toISOString(); try { if (dateOrLines === "lines") { logResult = await this.sshService.exec(`docker logs ${containerName} --tail=${lines} 2>&1`); } else { - logResult = await this.sshService.exec( - `docker logs ${containerName} --since=${sinceDate} --until=${untilDate} 2>&1` - ); + logResult = await this.sshService.exec(`docker logs ${containerName} --since=${sinceDate} --until=${untilDate} 2>&1`); } if (logResult.rc || !logResult.stdout || logResult.stderr) { diff --git a/launcher/src/backend/NodeUpdates.js b/launcher/src/backend/NodeUpdates.js index 289488a7f6..9d7c7e775b 100644 --- a/launcher/src/backend/NodeUpdates.js +++ b/launcher/src/backend/NodeUpdates.js @@ -150,9 +150,7 @@ export class NodeUpdates { */ async getCountOfUpdatableOSUpdate() { try { - const res = await this.nodeConnection.sshService.exec( - `LANG=C apt-get upgrade -s |grep -P '^\\d+ upgraded'|cut -d" " -f1` - ); + const res = await this.nodeConnection.sshService.exec(`LANG=C apt-get upgrade -s |grep -P '^\\d+ upgraded'|cut -d" " -f1`); return res.stdout; } catch (err) { @@ -185,7 +183,7 @@ export class NodeUpdates { * @returns {number} - playbook runtime */ async updatePackage(packages) { - let packagesListString = packages.join(','); + let packagesListString = packages.join(","); let extraVars = { stereum_role: "update-package", packages_list: packagesListString, diff --git a/launcher/src/backend/OneClickInstall.js b/launcher/src/backend/OneClickInstall.js index bc201e6113..d1c2ba8e2b 100755 --- a/launcher/src/backend/OneClickInstall.js +++ b/launcher/src/backend/OneClickInstall.js @@ -35,46 +35,13 @@ export class OneClickInstall { echo -e ${StringUtils.escapeStringForShell(YAML.stringify(settings))} > /etc/stereum/stereum.yaml`); await this.configManager.createMultiSetupYaml({}, ""); await this.nodeConnection.findStereumSettings(); - return await this.nodeConnection.prepareStereumNode( - this.nodeConnection.settings.stereum.settings.controls_install_path - ); + return await this.nodeConnection.prepareStereumNode(this.nodeConnection.settings.stereum.settings.controls_install_path); } //this is broken - async chooseClient(clients) { - clients = { - PRYSM: 24, - LIGHTHOUSE: 24, - NIMBUS: 24, - TEKU: 20, - }; - let buffer = []; - let clientDistribution = []; - let sum = 0; - let range = 0; - - Object.keys(clients).forEach((key) => { - buffer.push({ name: key, coverage: clients[key] }); - }); - - buffer.forEach((client) => { - sum += 100 / client.coverage; - }); - - buffer.forEach((client) => { - clientDistribution.push({ name: client.name, percentage: (100 / client.coverage / sum) * 100 }); - }); - - clientDistribution.forEach((client) => { - client.min = range; - range = range + client.percentage; - client.max = range; - }); - - const ran = Math.random() * 100; - const winner = clientDistribution.find((client) => client.min <= ran && client.max >= ran); - log.info(winner, ran); - return winner.name.toLowerCase(); + chooseClient(clients) { + let client = clients[Math.floor(Math.random() * clients.length)].toLowerCase(); + return client.charAt(0).toUpperCase() + client.slice(1); } clearSetup() { @@ -83,7 +50,6 @@ export class OneClickInstall { this.installDir = undefined; this.executionClient = undefined; this.setup = undefined; - this.choosenClient = undefined; this.network = undefined; this.mevboost = undefined; this.needsKeystore = []; @@ -293,9 +259,7 @@ export class OneClickInstall { this.extraServices.push( this.serviceManager.getService("LidoObolExitService", { ...args, - consensusClients: [this.beaconService].concat( - this.extraServices.filter((s) => s.service === "CharonService") - ), + consensusClients: [this.beaconService].concat(this.extraServices.filter((s) => s.service === "CharonService")), otherServices: this.extraServices.filter((s) => s.service === "ValidatorEjectorService"), }) ); @@ -378,17 +342,13 @@ export class OneClickInstall { this.executionClient.command = this.executionClient.command.filter((c) => !c.includes("--prune")); break; case "BesuService": - this.executionClient.command[this.executionClient.command.findIndex((c) => c.includes("--sync-mode=SNAP"))] = - "--sync-mode=FULL"; + this.executionClient.command[this.executionClient.command.findIndex((c) => c.includes("--sync-mode=SNAP"))] = "--sync-mode=FULL"; break; case "NethermindService": - this.executionClient.command[this.executionClient.command.findIndex((c) => c.includes("--config"))] += - "_archive"; + this.executionClient.command[this.executionClient.command.findIndex((c) => c.includes("--config"))] += "_archive"; this.executionClient.command[this.executionClient.command.findIndex((c) => c.includes("--Pruning.Mode="))] = "--Pruning.Mode=None"; - this.executionClient.command = this.executionClient.command.filter( - (c) => !c.includes("--Pruning.FullPruningTrigger") - ); + this.executionClient.command = this.executionClient.command.filter((c) => !c.includes("--Pruning.FullPruningTrigger")); break; } switch (this.beaconService.service) { @@ -419,20 +379,30 @@ export class OneClickInstall { } handleLidoTags(selectedPreset) { - if (selectedPreset == "obol") { + if (/lidocsm/.test(selectedPreset)) { const networkFeeAdress = { mainnet: "0x388C818CA8B9251b393131C08a736A67ccB19297", holesky: "0xE73a3602b99f1f913e72F8bdcBC235e206794Ac8", - } + }; const serviceFeeAdressCommand = { LighthouseValidatorService: "--suggested-fee-recipient=", LodestarValidatorService: "--suggestedFeeRecipient=", NimbusValidatorService: "--suggested-fee-recipient=", PrysmValidatorService: "--suggested-fee-recipient=", TekuValidatorService: "--validators-proposer-default-fee-recipient=", - } - this.validatorService.command[this.validatorService.command.findIndex((c) => c.includes(serviceFeeAdressCommand[this.validatorService.service]))] = - serviceFeeAdressCommand[this.validatorService.service] + networkFeeAdress[this.network]; + }; + this.validatorService.command[ + this.validatorService.command.findIndex((c) => c.includes(serviceFeeAdressCommand[this.validatorService.service])) + ] = serviceFeeAdressCommand[this.validatorService.service] + networkFeeAdress[this.network]; + } + if (this.extraServices.some((s) => s.service === "ValidatorEjectorService")) { + const moduleIDs = { + lidocsm: "4", + lidossv: "2", + lidoobol: "2", + }; + let ejector = this.extraServices.find((s) => s.service === "ValidatorEjectorService"); + ejector.env.STAKING_MODULE_ID = moduleIDs[selectedPreset]; } } @@ -483,19 +453,16 @@ export class OneClickInstall { this.clearSetup(); this.setup = setup; this.network = network; - let services = [ - "GethService", - "GrafanaService", - "PrometheusNodeExporterService", - "PrometheusService", - "NotificationService", - ]; + let services = ["GrafanaService", "PrometheusNodeExporterService", "PrometheusService", "NotificationService"]; - this.choosenClient = await this.chooseClient(); - this.choosenClient = this.choosenClient.charAt(0).toUpperCase() + this.choosenClient.slice(1); + const selectedCC_VC = this.chooseClient(["PRYSM", "LIGHTHOUSE", "NIMBUS", "TEKU", "LODESTAR"]); - services.push(this.choosenClient + "ValidatorService"); - services.push(this.choosenClient + "BeaconService"); + services.push(selectedCC_VC + "ValidatorService"); + services.push(selectedCC_VC + "BeaconService"); + + const selectedEC = this.chooseClient(["GETH", "BESU", "NETHERMIND"]); + + services.push(selectedEC + "Service"); if (network === "gnosis") services = [ @@ -518,51 +485,23 @@ export class OneClickInstall { services.push("SSVNetworkService"); break; case "obol": - services = [ - "GethService", - "LighthouseBeaconService", - "TekuValidatorService", - "CharonService", - "GrafanaService", - "PrometheusNodeExporterService", - "PrometheusService", - "NotificationService", - ]; - break; - case "rocketpool": - services.push("ROCKETPOOL"); + services.push("FlashbotsMevBoostService", "CharonService"); break; case "stereum on arm": services = services.filter( - (s) => - !["GrafanaService", "PrometheusNodeExporterService", "PrometheusService", "NotificationService"].includes(s) + (s) => !["GrafanaService", "PrometheusNodeExporterService", "PrometheusService", "NotificationService"].includes(s) ); break; case "archive": break; case "lidoobol": - services = [ - "NethermindService", - "LighthouseBeaconService", - "LodestarValidatorService", - "GrafanaService", - "PrometheusNodeExporterService", - "PrometheusService", - "NotificationService", - ]; services.push("LidoObolExitService", "CharonService", "ValidatorEjectorService", "FlashbotsMevBoostService"); break; case "lidossv": services.push("SSVNetworkService", "SSVDKGService", "FlashbotsMevBoostService"); break; case "lidocsm": - services.push( - "FlashbotsMevBoostService", - "KeysAPIService", - "ValidatorEjectorService", - "KuboIPFSService", - "LCOMService" - ); + services.push("FlashbotsMevBoostService", "KeysAPIService", "ValidatorEjectorService", "KuboIPFSService", "LCOMService"); } return services; } diff --git a/launcher/src/backend/SSHService.js b/launcher/src/backend/SSHService.js index 29211b56d2..6c59c4ede7 100755 --- a/launcher/src/backend/SSHService.js +++ b/launcher/src/backend/SSHService.js @@ -211,8 +211,7 @@ export class SSHService { } async exec(command, useSudo = true, useRoot = true) { - const ensureSudoCommand = - `sudo -u ${useRoot ? "root" : this.connectionInfo.user} -i <<'=====EOF'\n` + command + `\n=====EOF`; + const ensureSudoCommand = `sudo -u ${useRoot ? "root" : this.connectionInfo.user} -i <<'=====EOF'\n` + command + `\n=====EOF`; return this.execCommand(useSudo ? ensureSudoCommand : command); } @@ -298,11 +297,7 @@ export class SSHService { while (i--) { // loop backwards to splice array from specific ports let tunnel = this.tunnels[i]; - if ( - Array.isArray(onlySpecificPorts) && - onlySpecificPorts.length && - !onlySpecificPorts.includes(tunnel.config.localPort) - ) { + if (Array.isArray(onlySpecificPorts) && onlySpecificPorts.length && !onlySpecificPorts.includes(tunnel.config.localPort)) { continue; } tunnel.server.close(); @@ -399,10 +394,7 @@ export class SSHService { try { if (sshDirPath.endsWith("/")) sshDirPath = sshDirPath.slice(0, -1, ""); //if path ends with '/' remove it let newKeys = keys.join("\n"); - let result = await this.exec( - `echo -e ${StringUtils.escapeStringForShell(newKeys)} > ${sshDirPath}/authorized_keys`, - false - ); + let result = await this.exec(`echo -e ${StringUtils.escapeStringForShell(newKeys)} > ${sshDirPath}/authorized_keys`, false); if (SSHService.checkExecError(result)) { throw new Error("Failed writing authorized keys:\n" + SSHService.extractExecError(result)); } diff --git a/launcher/src/backend/SSHServiceTunnel.js b/launcher/src/backend/SSHServiceTunnel.js index ad77d8d180..91ea7224ee 100755 --- a/launcher/src/backend/SSHServiceTunnel.js +++ b/launcher/src/backend/SSHServiceTunnel.js @@ -55,25 +55,19 @@ async function createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOpt autoClose(server, connection); } try { - conn.forwardOut( - forwardOptions.srcAddr, - forwardOptions.srcPort, - forwardOptions.dstAddr, - forwardOptions.dstPort, - (err, stream) => { - if (err) { - return err; - } - connection.pipe(stream).pipe(connection); + conn.forwardOut(forwardOptions.srcAddr, forwardOptions.srcPort, forwardOptions.dstAddr, forwardOptions.dstPort, (err, stream) => { + if (err) { + return err; } - ); + connection.pipe(stream).pipe(connection); + }); } catch (e) { return e; } }); server.on("close", () => conn.end()); - return [server, conn] + return [server, conn]; } exports.createTunnel = createTunnel; diff --git a/launcher/src/backend/ServiceManager.js b/launcher/src/backend/ServiceManager.js index 2a349d64c2..98a66afe1b 100755 --- a/launcher/src/backend/ServiceManager.js +++ b/launcher/src/backend/ServiceManager.js @@ -310,8 +310,7 @@ export class ServiceManager { //add checkpointSync if Url was send if (checkpointUrl) { command.push(checkpointCommands[client.service] + checkpointUrl); - if (genesisSyncCommands[client.service]) - command = command.filter((c) => !c.includes(genesisSyncCommands[client.service])); + if (genesisSyncCommands[client.service]) command = command.filter((c) => !c.includes(genesisSyncCommands[client.service])); } else { //add genesisSync if no Url was send if (genesisSyncCommands[client.service]) command.push(genesisSyncCommands[client.service]); @@ -331,8 +330,7 @@ export class ServiceManager { getWorkindDir(service) { if (service.volumes.length > 0) { let volumeWithID = service.volumes.find((v) => v.destinationPath.includes(service.id)); - if (volumeWithID && volumeWithID.destinationPath) - return volumeWithID.destinationPath.replace(new RegExp(`(?<=${service.id}).*`), ""); + if (volumeWithID && volumeWithID.destinationPath) return volumeWithID.destinationPath.replace(new RegExp(`(?<=${service.id}).*`), ""); } return undefined; } @@ -351,28 +349,24 @@ export class ServiceManager { for (let task of tasks) { let ssvConfig; let service = services.find((s) => s.id === task.service.config.serviceID); - let dependencies = task.data.executionClients - .concat(task.data.consensusClients, task.data.otherServices) - .map((s) => - services.find((e) => { - if (e.id === s.config.serviceID) { - return true; - } else if ( - newInstallTasks && - newInstallTasks.length > 0 && - e.id === newInstallTasks.find((i) => i.service.id === s.id).service.config.serviceID - ) { - return true; - } - return false; - }) - ); + let dependencies = task.data.executionClients.concat(task.data.consensusClients, task.data.otherServices).map((s) => + services.find((e) => { + if (e.id === s.config.serviceID) { + return true; + } else if ( + newInstallTasks && + newInstallTasks.length > 0 && + e.id === newInstallTasks.find((i) => i.service.id === s.id).service.config.serviceID + ) { + return true; + } + return false; + }) + ); if (service.service === "FlashbotsMevBoostService") { modifiedServices.push(service); - let dependenciesToRemove = services.filter((s) => - s.dependencies.mevboost.map((m) => m.id).includes(service.id) - ); + let dependenciesToRemove = services.filter((s) => s.dependencies.mevboost.map((m) => m.id).includes(service.id)); dependenciesToRemove.forEach((dependency) => { modifiedServices.push(this.removeDependencies(dependency, service)); }); @@ -499,12 +493,8 @@ export class ServiceManager { }, ]; this.addENVConnction(service, dependencies, keyValuePairs); - service.dependencies.executionClients = dependencies.filter( - (d) => typeof d.buildExecutionClientHttpEndpointUrl === "function" - ); - service.dependencies.consensusClients = dependencies.filter( - (d) => typeof d.buildConsensusClientHttpEndpointUrl === "function" - ); + service.dependencies.executionClients = dependencies.filter((d) => typeof d.buildExecutionClientHttpEndpointUrl === "function"); + service.dependencies.consensusClients = dependencies.filter((d) => typeof d.buildConsensusClientHttpEndpointUrl === "function"); return service; case "KeysAPI": // create a new function to handle dependencies for env vars @@ -521,12 +511,8 @@ export class ServiceManager { }, ]; this.addENVConnction(service, dependencies, keyValuePairs); - service.dependencies.executionClients = dependencies.filter( - (d) => typeof d.buildExecutionClientHttpEndpointUrl === "function" - ); - service.dependencies.consensusClients = dependencies.filter( - (d) => typeof d.buildConsensusClientHttpEndpointUrl === "function" - ); + service.dependencies.executionClients = dependencies.filter((d) => typeof d.buildExecutionClientHttpEndpointUrl === "function"); + service.dependencies.consensusClients = dependencies.filter((d) => typeof d.buildConsensusClientHttpEndpointUrl === "function"); return service; default: return service; @@ -565,9 +551,7 @@ export class ServiceManager { command = command.filter((c) => !c.includes(endpointCommand)); let newProps; if (fullCommand) { - newProps = [this.formatCommand(fullCommand, endpointCommand, filter, dependencies)].filter( - (c) => c !== undefined - ); + newProps = [this.formatCommand(fullCommand, endpointCommand, filter, dependencies)].filter((c) => c !== undefined); } else { newProps = endpointCommand + dependencies.map(filter).join(); } @@ -773,9 +757,7 @@ export class ServiceManager { ); } if (serviceToDelete.service === "KeysAPIService") { - await this.nodeConnection.sshService.exec( - `docker stop cachingDB-${serviceToDelete.id} && docker rm cachingDB-${serviceToDelete.id}` - ); + await this.nodeConnection.sshService.exec(`docker stop cachingDB-${serviceToDelete.id} && docker rm cachingDB-${serviceToDelete.id}`); } await this.nodeConnection.runPlaybook("Delete Service", { stereum_role: "delete-service", @@ -921,12 +903,7 @@ export class ServiceManager { case "LighthouseValidatorService": ports = [new ServicePort("127.0.0.1", args.port ? args.port : 5062, 5062, servicePortProtocol.tcp)]; - return LighthouseValidatorService.buildByUserInput( - args.network, - ports, - args.installDir + "/lighthouse", - args.consensusClients - ); + return LighthouseValidatorService.buildByUserInput(args.network, ports, args.installDir + "/lighthouse", args.consensusClients); case "PrysmBeaconService": ports = [ @@ -946,12 +923,7 @@ export class ServiceManager { case "PrysmValidatorService": ports = [new ServicePort("127.0.0.1", args.port ? args.port : 7500, 7500, servicePortProtocol.tcp)]; - return PrysmValidatorService.buildByUserInput( - args.network, - ports, - args.installDir + "/prysm", - args.consensusClients - ); + return PrysmValidatorService.buildByUserInput(args.network, ports, args.installDir + "/prysm", args.consensusClients); case "LodestarBeaconService": //LodestarBeaconService @@ -972,12 +944,7 @@ export class ServiceManager { case "LodestarValidatorService": //LodestarValidatorService ports = [new ServicePort("127.0.0.1", args.port ? args.port : 5062, 5062, servicePortProtocol.tcp)]; - return LodestarValidatorService.buildByUserInput( - args.network, - ports, - args.installDir + "/lodestar", - args.consensusClients - ); + return LodestarValidatorService.buildByUserInput(args.network, ports, args.installDir + "/lodestar", args.consensusClients); case "NimbusBeaconService": ports = [ @@ -996,12 +963,7 @@ export class ServiceManager { case "NimbusValidatorService": ports = []; - return NimbusValidatorService.buildByUserInput( - args.network, - ports, - args.installDir + "/nimbus", - args.consensusClients - ); + return NimbusValidatorService.buildByUserInput(args.network, ports, args.installDir + "/nimbus", args.consensusClients); case "TekuBeaconService": ports = [ @@ -1021,12 +983,7 @@ export class ServiceManager { case "TekuValidatorService": ports = []; - return TekuValidatorService.buildByUserInput( - args.network, - ports, - args.installDir + "/teku", - args.consensusClients - ); + return TekuValidatorService.buildByUserInput(args.network, ports, args.installDir + "/teku", args.consensusClients); case "PrometheusNodeExporterService": return PrometheusNodeExporterService.buildByUserInput(args.network); @@ -1081,12 +1038,7 @@ export class ServiceManager { case "ExternalExecutionService": ports = []; - return ExternalExecutionService.buildByUserInput( - args.network, - args.installDir + "/externalExecution", - args.source, - args.jwtToken - ); + return ExternalExecutionService.buildByUserInput(args.network, args.installDir + "/externalExecution", args.source, args.jwtToken); case "ExternalConsensusService": ports = []; return ExternalConsensusService.buildByUserInput( @@ -1116,10 +1068,7 @@ export class ServiceManager { args.otherServices ); case "SSVDKGService": - ports = [ - new ServicePort(null, 3030, 3030, servicePortProtocol.udp), - new ServicePort(null, 3030, 3030, servicePortProtocol.tcp), - ]; + ports = [new ServicePort(null, 3030, 3030, servicePortProtocol.udp), new ServicePort(null, 3030, 3030, servicePortProtocol.tcp)]; return SSVDKGService.buildByUserInput( args.network, ports, @@ -1164,9 +1113,7 @@ export class ServiceManager { keyAPI.env.DB_HOST = `cachingDB-${keyAPI.id}`; } catch (err) { log.error("Creating CachingDB failed: ", err); - await this.nodeConnection.sshService.exec( - `docker stop cachingDB-${keyAPI.id} && docker rm cachingDB-${keyAPI.id}` - ); + await this.nodeConnection.sshService.exec(`docker stop cachingDB-${keyAPI.id} && docker rm cachingDB-${keyAPI.id}`); } } @@ -1202,9 +1149,7 @@ export class ServiceManager { ); } catch (err) { log.error("Creating SlashingDB failed: ", err); - await this.nodeConnection.sshService.exec( - `docker stop slashingdb-${web3signer.id} && docker rm slashingdb-${web3signer.id}` - ); + await this.nodeConnection.sshService.exec(`docker stop slashingdb-${web3signer.id} && docker rm slashingdb-${web3signer.id}`); } } @@ -1212,9 +1157,7 @@ export class ServiceManager { for (const service of services) { await this.manageServiceState(service.id, "started"); const workingDir = this.getWorkindDir(service); - await this.nodeConnection.sshService.exec( - "docker cp stereum-" + service.id + ":/opt/web3signer/migrations/postgresql " + workingDir - ); + await this.nodeConnection.sshService.exec("docker cp stereum-" + service.id + ":/opt/web3signer/migrations/postgresql " + workingDir); await this.manageServiceState(service.id, "stopped"); service.command = service.command.filter((c) => c != "--slashing-protection-enabled=false"); await this.createSlashingDB(service, workingDir); @@ -1224,18 +1167,12 @@ export class ServiceManager { async createKeystores(services) { for (const service of services) { - if ( - service.service === "NimbusValidatorService" || - (service.service === "NimbusBeaconService" && service.configVersion < 2) - ) { + if (service.service === "NimbusValidatorService" || (service.service === "NimbusBeaconService" && service.configVersion < 2)) { const valDir = service.volumes.find((vol) => vol.servicePath === "/opt/app/validators").destinationPath; const token = StringUtils.createRandomString(); await this.nodeConnection.sshService.exec(`mkdir -p ${valDir}`); await this.nodeConnection.sshService.exec(`echo ${token} > ${valDir}/api-token.txt`); - } else if ( - service.service === "TekuValidatorService" || - (service.service === "TekuBeaconService" && service.configVersion < 2) - ) { + } else if (service.service === "TekuValidatorService" || (service.service === "TekuBeaconService" && service.configVersion < 2)) { const dataDir = service.volumes.find((vol) => vol.servicePath === "/opt/app/data").destinationPath; const password = StringUtils.createRandomString(); await this.nodeConnection.sshService.exec("apt install -y openjdk-8-jre-headless"); @@ -1259,18 +1196,13 @@ export class ServiceManager { if (config.ssv_sk) { replacementString = "OperatorPrivateKey: " + config.ssv_sk; } else { - replacementString = - "KeyStore:\n PrivateKeyFile: /secrets/encrypted_private_key.json\n PasswordFile: /secrets/password"; + replacementString = "KeyStore:\n PrivateKeyFile: /secrets/encrypted_private_key.json\n PasswordFile: /secrets/password"; } // prepare service's config file const dataDir = service.volumes.find((vol) => vol.servicePath === "/data").destinationPath; - const escapedConfigFile = StringUtils.escapeStringForShell( - ssvConfig.replace(/^OperatorPrivateKey.*/gm, replacementString) - ); - this.nodeConnection.sshService.exec( - `mkdir -p ${dataDir} && echo ${escapedConfigFile} > ${dataDir}/config.yaml` - ); + const escapedConfigFile = StringUtils.escapeStringForShell(ssvConfig.replace(/^OperatorPrivateKey.*/gm, replacementString)); + this.nodeConnection.sshService.exec(`mkdir -p ${dataDir} && echo ${escapedConfigFile} > ${dataDir}/config.yaml`); } else if (service.service.includes("External")) { const extConnDir = service.volumes .find((vol) => vol.destinationPath.includes("link.txt")) @@ -1344,10 +1276,7 @@ export class ServiceManager { }); let DVTInstalls = tasks.filter((t) => /SSVNetwork|Charon/.test(t.service.service)); DVTInstalls.forEach((t) => { - if ( - t.service.service == "SSVNetworkService" && - services.filter((s) => s.service === "SSVNetworkService").length - ) { + if (t.service.service == "SSVNetworkService" && services.filter((s) => s.service === "SSVNetworkService").length) { // TODO: Make SSVNetworkService multiservice (which depends also on SSVDKGService) log.error("Multiple SSVNetworkService services currently not supported - ignoring setup!"); return; @@ -1358,9 +1287,7 @@ export class ServiceManager { setupAndServiceIds[service.id] = t.data.setupId; newServices.push(service); }); - let VLInstalls = tasks.filter( - (t) => t.service.category === "validator" && !/SSVNetwork|Charon/.test(t.service.service) - ); + let VLInstalls = tasks.filter((t) => t.service.category === "validator" && !/SSVNetwork|Charon/.test(t.service.service)); VLInstalls.forEach((t) => { this.updateInfoForDependencies(t, services, newServices, ELInstalls, CLInstalls, undefined, DVTInstalls); let service = this.getService(t.service.service, t.data); @@ -1457,10 +1384,7 @@ export class ServiceManager { await this.createKeystores( newServices.filter( (s) => - s.service.includes("Teku") || - s.service.includes("Nimbus") || - s.service.includes("SSVNetwork") || - s.service.includes("External") + s.service.includes("Teku") || s.service.includes("Nimbus") || s.service.includes("SSVNetwork") || s.service.includes("External") ) ); await this.prepareSSVDKG(newServices.find((s) => s.service === "SSVDKGService")); @@ -1658,10 +1582,7 @@ export class ServiceManager { // 2. Adjust SSV operator ID in DKG config if (ssvTotalConfig) { // Set operator ID to last known operator ID (revert or 0) in DKG config file (if needed) - if ( - ssvTotalConfig.lastKnownOperatorId && - ssvDkgTotalConfig.operatorId != ssvTotalConfig.lastKnownOperatorId - ) { + if (ssvTotalConfig.lastKnownOperatorId && ssvDkgTotalConfig.operatorId != ssvTotalConfig.lastKnownOperatorId) { log.silly("SSVNetworkService exists"); log.info(`Update operator ID in DKG config file to ${ssvTotalConfig.lastKnownOperatorId}`); ssvDkgTotalConfig.ssvDkgConfig.operatorID = parseInt(ssvTotalConfig.lastKnownOperatorId, 10); @@ -1720,8 +1641,7 @@ export class ServiceManager { //make sure there are no double tasks (for example: TekuBeaconService, TekuValidatorService share the same id) static uniqueByID(job) { return (value, index, self) => - self.map((t) => t.service.config.serviceID).indexOf(value.service.config.serviceID) === index && - value.content === job; + self.map((t) => t.service.config.serviceID).indexOf(value.service.config.serviceID) === index && value.content === job; } //remove all service data @@ -1912,12 +1832,7 @@ export class ServiceManager { return serviceNameConfig; } catch (error) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Export Failed`, - false, - `Failed to export setup: ${error}` - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Export Failed`, false, `Failed to export setup: ${error}`); console.error(`Failed to export setup: ${error}`); } finally { this.nodeConnection.taskManager.otherTasksHandler(ref); @@ -1950,12 +1865,7 @@ export class ServiceManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Export Configuration Completed`, true); return serviceNameConfig; } catch (error) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Export Failed`, - false, - `Failed to export config: ${error}` - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Export Failed`, false, `Failed to export config: ${error}`); console.error(`Failed to export config: ${error}`); } finally { this.nodeConnection.taskManager.otherTasksHandler(ref); @@ -2018,9 +1928,7 @@ export class ServiceManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Wrote multi setup`, true); let services = await this.readServiceConfigurations(); - let importingSetupServices = services.filter((service) => - multiSetup[Object.keys(multiSetup)[0]].services.includes(service.id) - ); + let importingSetupServices = services.filter((service) => multiSetup[Object.keys(multiSetup)[0]].services.includes(service.id)); await Promise.all( importingSetupServices.map(async (service) => { @@ -2043,12 +1951,7 @@ export class ServiceManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Import Configuration Completed`, true); return runRefs; } catch (error) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Import Failed`, - false, - `Failed to import config: ${error}` - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Import Failed`, false, `Failed to import config: ${error}`); console.error(`Failed to import config: ${error}`); } finally { this.nodeConnection.taskManager.otherTasksHandler(ref); @@ -2151,12 +2054,7 @@ export class ServiceManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Import Configuration Completed`, true); return runRefs; } catch (error) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Import Failed`, - false, - `Failed to import config: ${error}` - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Import Failed`, false, `Failed to import config: ${error}`); console.error(`Failed to import config: ${error}`); } finally { this.nodeConnection.taskManager.otherTasksHandler(ref); @@ -2197,9 +2095,7 @@ export class ServiceManager { async beaconchainMonitoringModification(data) { let services = await this.readServiceConfigurations(); let selectedValidator = services.find((service) => service.id === data.selectedVal); - let firstConsensusClient = services.find( - (service) => service.id === selectedValidator.dependencies.consensusClients[0].id - ); + let firstConsensusClient = services.find((service) => service.id === selectedValidator.dependencies.consensusClients[0].id); const metricsExporterCommands = { LighthouseValidatorService: "--monitoring-endpoint=", @@ -2275,10 +2171,7 @@ export class ServiceManager { `--system.partition=/host/rootfs` ); if (selectedValidator.service == "PrysmValidatorService") { - metricsExporter.command.push( - `--validator.type=prysm`, - `--validator.address=http://stereum-${selectedValidator.id}:8081/metrics` - ); + metricsExporter.command.push(`--validator.type=prysm`, `--validator.address=http://stereum-${selectedValidator.id}:8081/metrics`); } if (firstConsensusClient.service == "PrysmBeaconService") { metricsExporter.command.push( @@ -2350,18 +2243,14 @@ export class ServiceManager { let services = await this.readServiceConfigurations(); let selectedValidator = services.find((service) => service.id === data.selectedVal); - let firstConsensusClient = services.find( - (service) => service.id === selectedValidator.dependencies.consensusClients[0].id - ); + let firstConsensusClient = services.find((service) => service.id === selectedValidator.dependencies.consensusClients[0].id); switch (selectedValidator.service) { case "LighthouseValidatorService": case "TekuValidatorService": case "LodestarValidatorService": await this.manageServiceState(selectedValidator.id, "stopped"); - metricsCommandIndex = selectedValidator.command.findIndex((c) => - c.includes(metricsExporterCommands[selectedValidator.service]) - ); + metricsCommandIndex = selectedValidator.command.findIndex((c) => c.includes(metricsExporterCommands[selectedValidator.service])); if (metricsCommandIndex > -1) { selectedValidator.command.splice(metricsCommandIndex, 1); } diff --git a/launcher/src/backend/TaskManager.js b/launcher/src/backend/TaskManager.js index b24f044429..6c92f80f42 100755 --- a/launcher/src/backend/TaskManager.js +++ b/launcher/src/backend/TaskManager.js @@ -1,6 +1,6 @@ export class TaskManager { constructor(nodeConnection) { - this.nodeConnection = nodeConnection + this.nodeConnection = nodeConnection; this.tasks = []; //all tasks this.polishedTasks = []; //all tasks prepared for displaying this.finishedPlaybooks = []; //finished playbook tasks @@ -59,7 +59,7 @@ export class TaskManager { let logs = ""; try { logs = await this.nodeConnection.playbookStatus(task.ref); - } catch (err) { } + } catch (err) {} let buffer = logs.split("\n\n"); buffer.pop(); task.subTasks = []; @@ -127,8 +127,9 @@ export class TaskManager { name: subTask.name, action: subTask.name, status: subTask.status ? "OK" : "FAILED", - data: `TASK: ${subTask.name}\nACTION: ${subTask.name}\nCATEGORY: ${subTask.status ? "OK" : "FAILED" - }\nDATA: ${subTask.data ? subTask.data : "There is no data for these kind of tasks ¯\\_(ツ)_/¯"}`, + data: `TASK: ${subTask.name}\nACTION: ${subTask.name}\nCATEGORY: ${subTask.status ? "OK" : "FAILED"}\nDATA: ${ + subTask.data ? subTask.data : "There is no data for these kind of tasks ¯\\_(ツ)_/¯" + }`, }; }); if (this.finishedOtherTasks.map((other) => other.otherRunRef).includes(task.otherRunRef)) { diff --git a/launcher/src/backend/TekuGasLimitConfig.js b/launcher/src/backend/TekuGasLimitConfig.js index b939d8abb8..1f2bd1bcca 100644 --- a/launcher/src/backend/TekuGasLimitConfig.js +++ b/launcher/src/backend/TekuGasLimitConfig.js @@ -1,11 +1,10 @@ -export class TekuGasLimitConfig{ +export class TekuGasLimitConfig { constructor(nodeConnection) { this.nodeConnection = nodeConnection; } - async createGasConfigFile(gasLimit, feeRecipient, configPath){ - const configContent = - `{ + async createGasConfigFile(gasLimit, feeRecipient, configPath) { + const configContent = `{ "default_config": { "fee_recipient": "${feeRecipient}", "builder": { @@ -17,23 +16,21 @@ export class TekuGasLimitConfig{ await this.nodeConnection.sshService.exec(`echo '${configContent}' > ${configPath}/gas_config.json`); } - async removeGasConfigFile(configPath){ + async removeGasConfigFile(configPath) { await this.nodeConnection.sshService.exec(`rm -f ${configPath}/gas_config.json`); } - async readGasConfigFile(configPath){ - let result = await this.nodeConnection.sshService.exec(`test -f ${configPath}/gas_config.json`) - if(result.rc == 0){ - let gasLimit = await this.nodeConnection.sshService.exec(`cat ${configPath}/gas_config.json`) - if(gasLimit.includes("gas_limit")){ - gasLimit = gasLimit.stdout.match(/^.*gas_limit.*$/gm)[0].split(':')[1]; + async readGasConfigFile(configPath) { + let result = await this.nodeConnection.sshService.exec(`test -f ${configPath}/gas_config.json`); + if (result.rc == 0) { + let gasLimit = await this.nodeConnection.sshService.exec(`cat ${configPath}/gas_config.json`); + if (gasLimit.includes("gas_limit")) { + gasLimit = gasLimit.stdout.match(/^.*gas_limit.*$/gm)[0].split(":")[1]; return gasLimit; - } - else{ + } else { return ""; } - } - else{ + } else { return ""; } } diff --git a/launcher/src/backend/ValidatorAccountManager.js b/launcher/src/backend/ValidatorAccountManager.js index 438fa035a3..a799ff9262 100755 --- a/launcher/src/backend/ValidatorAccountManager.js +++ b/launcher/src/backend/ValidatorAccountManager.js @@ -27,9 +27,7 @@ export class ValidatorAccountManager { if (slashingDB) var slashing_protection_content = JSON.parse(readFileSync(slashingDB, { encoding: "utf8" })); let passwords = Array(files.length).fill(password); const content = files.map((file, index) => { - const passwordFile = passwordFiles.find( - (p) => path.basename(p.name, ".txt") === path.basename(file.name, ".json") - ); + const passwordFile = passwordFiles.find((p) => path.basename(p.name, ".txt") === path.basename(file.name, ".json")); if (passwordFile) { passwords[index] = readFileSync(passwordFile.path, { encoding: "utf8" }); } @@ -65,9 +63,7 @@ export class ValidatorAccountManager { if (pubkeys && pubkeys.length < 11) { try { for (const pubkey of pubkeys) { - let latestEpochsResponse = await axios.get( - networks[client.network].dataEndpoint + "/validator/" + pubkey + "/attestations" - ); + let latestEpochsResponse = await axios.get(networks[client.network].dataEndpoint + "/validator/" + pubkey + "/attestations"); if (latestEpochsResponse.status === 200 && latestEpochsResponse.data.data.length > 0) { for (let i = 0; i < 2; i++) { @@ -98,22 +94,15 @@ export class ValidatorAccountManager { .volumes.find((volume) => volume.includes("passwords")) .split(":")[0]; - const walletPassword = await this.nodeConnection.sshService.exec(`cat ${passwords_path}/wallet-password`) - const walletDir = await this.nodeConnection.sshService.exec(`ls ${wallet_path}/direct/accounts`) + const walletPassword = await this.nodeConnection.sshService.exec(`cat ${passwords_path}/wallet-password`); + const walletDir = await this.nodeConnection.sshService.exec(`ls ${wallet_path}/direct/accounts`); if (walletPassword.rc != 0 || walletDir.rc != 0) { log.error("No Wallet found"); log.info("Generating one"); - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Check Wallet`, - true, - "No Wallet found, generating one" - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Check Wallet`, true, "No Wallet found, generating one"); //generate wallet password - await this.nodeConnection.sshService.exec( - `echo ${StringUtils.createRandomString()} > ${passwords_path}/wallet-password` - ); + await this.nodeConnection.sshService.exec(`echo ${StringUtils.createRandomString()} > ${passwords_path}/wallet-password`); await this.nodeConnection.sshService.exec(`chmod 700 ${passwords_path}/wallet-password`); await this.nodeConnection.sshService.exec(`chown 2000:2000 ${passwords_path}/wallet-password`); //Prysm - Create wallet for account(s) @@ -126,15 +115,8 @@ export class ValidatorAccountManager { await Promise.all([this.serviceManager.manageServiceState(client.id, "stopped")]); await Promise.all([this.serviceManager.manageServiceState(client.id, "started")]); - await this.nodeConnection.sshService.exec( - `chmod 600 ${wallet_path}/direct/accounts/all-accounts.keystore.json` - ); - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Generated Wallet`, - true, - "Waiting 30 Seconds for Client" - ); + await this.nodeConnection.sshService.exec(`chmod 600 ${wallet_path}/direct/accounts/all-accounts.keystore.json`); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Generated Wallet`, true, "Waiting 30 Seconds for Client"); await Sleep(30000); } break; @@ -150,9 +132,7 @@ export class ValidatorAccountManager { if ((await this.nodeConnection.sshService.exec(`cat ${validator_path}/api-token.txt`)).rc === 1) { log.error("Couldn't read API-Token"); log.info("Generating one"); - await this.nodeConnection.sshService.exec( - `echo ${StringUtils.createRandomString()} > ${validator_path}/api-token.txt` - ); + await this.nodeConnection.sshService.exec(`echo ${StringUtils.createRandomString()} > ${validator_path}/api-token.txt`); await this.serviceManager.manageServiceState(client.id, "stopped"); await this.serviceManager.manageServiceState(client.id, "started"); await Sleep(30000); @@ -182,10 +162,7 @@ export class ValidatorAccountManager { async importKey(serviceID) { const ref = StringUtils.createRandomString(); - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Importing ${this.batches.map((b) => b.keystores).flat().length} Keys` - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Importing ${this.batches.map((b) => b.keystores).flat().length} Keys`); let services = await this.serviceManager.readServiceConfigurations(); let client = services.find((service) => service.id === serviceID); @@ -232,12 +209,7 @@ export class ValidatorAccountManager { this.nodeConnection.taskManager.otherTasksHandler(ref); return message; } catch (err) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Import Failed`, - false, - "Validator Import Failed:\n" + err - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Import Failed`, false, "Validator Import Failed:\n" + err); this.nodeConnection.taskManager.otherTasksHandler(ref); log.error("Validator Import Failed:\n", err); return "Validator Import Failed:\n" + err; @@ -271,12 +243,7 @@ export class ValidatorAccountManager { this.nodeConnection.taskManager.otherTasksHandler(ref); return data; } catch (err) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Listing Keys Failed`, - false, - "Listing Validators Failed:\n" + err - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Listing Keys Failed`, false, "Listing Validators Failed:\n" + err); this.nodeConnection.taskManager.otherTasksHandler(ref); log.error("Listing Validators Failed:\n", err); return { data: [] }; @@ -309,12 +276,7 @@ export class ValidatorAccountManager { if (picked) return data.slashing_protection; return data; } catch (err) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Deleting Keys Failed`, - false, - "Deleting Validators Failed:\n" + err - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Deleting Keys Failed`, false, "Deleting Validators Failed:\n" + err); this.nodeConnection.taskManager.otherTasksHandler(ref); log.error("Deleting Validators Failed:\n", err); return err; @@ -327,7 +289,8 @@ export class ValidatorAccountManager { const curlTag = await this.nodeConnection.ensureCurlImage(); let command = [ "docker run --rm --network=stereum curlimages/curl:" + curlTag, - `curl ${service.service.includes("Teku") ? "--insecure https" : "http"}://stereum-${service.id}:${validatorPorts[service.service] + `curl ${service.service.includes("Teku") ? "--insecure https" : "http"}://stereum-${service.id}:${ + validatorPorts[service.service] }${apiPath}`, `-X ${method.toUpperCase()}`, `-H 'Content-Type: application/json'`, @@ -419,13 +382,7 @@ export class ValidatorAccountManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Setting Fee Recipient`); //Push the task to the task manager try { let client = await this.nodeConnection.readServiceConfiguration(serviceID); - const result = await this.keymanagerAPI( - client, - "POST", - `/eth/v1/validator/${pubKey}/feerecipient`, - { ethaddress: address }, - ["-i"] - ); + const result = await this.keymanagerAPI(client, "POST", `/eth/v1/validator/${pubKey}/feerecipient`, { ethaddress: address }, ["-i"]); //Error handling if (SSHService.checkExecError(result) && result.stderr) throw SSHService.extractExecError(result); @@ -456,9 +413,7 @@ export class ValidatorAccountManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Deleting Fee Recipient`); //Push the task to the task manager try { let client = await this.nodeConnection.readServiceConfiguration(serviceID); - const result = await this.keymanagerAPI(client, "DELETE", `/eth/v1/validator/${pubKey}/feerecipient`, null, [ - "-i", - ]); + const result = await this.keymanagerAPI(client, "DELETE", `/eth/v1/validator/${pubKey}/feerecipient`, null, ["-i"]); //Error handling if (SSHService.checkExecError(result) && result.stderr) throw SSHService.extractExecError(result); @@ -498,16 +453,12 @@ export class ValidatorAccountManager { switch (service) { case "lighthouse": config = `default: ${graffiti}`; - await this.nodeConnection.sshService.exec( - "echo " + StringUtils.escapeStringForShell(config) + " > " + graffitiDir - ); + await this.nodeConnection.sshService.exec("echo " + StringUtils.escapeStringForShell(config) + " > " + graffitiDir); break; case "prysm": config = `default: "${graffiti}"`; - await this.nodeConnection.sshService.exec( - "echo " + StringUtils.escapeStringForShell(config) + " > " + graffitiDir - ); + await this.nodeConnection.sshService.exec("echo " + StringUtils.escapeStringForShell(config) + " > " + graffitiDir); break; case "nimbus": { @@ -529,9 +480,7 @@ export class ValidatorAccountManager { case "teku": config = graffiti; - await this.nodeConnection.sshService.exec( - "echo " + StringUtils.escapeStringForShell(config) + " > " + graffitiDir - ); + await this.nodeConnection.sshService.exec("echo " + StringUtils.escapeStringForShell(config) + " > " + graffitiDir); break; default: @@ -550,8 +499,7 @@ export class ValidatorAccountManager { //if the argument is an array of keys, add them to the current keys if they don't exist if (Array.isArray(keys)) { keys.forEach((key) => { - if (!currentKeys[key]) - currentKeys[key] = { keyName: "", groupName: "", groupID: null, validatorClientID: null }; + if (!currentKeys[key]) currentKeys[key] = { keyName: "", groupName: "", groupID: null, validatorClientID: null }; }); await this.nodeConnection.sshService.exec( "echo -e " + StringUtils.escapeStringForShell(YAML.stringify(currentKeys)) + " > /etc/stereum/keys.yaml" @@ -584,16 +532,12 @@ export class ValidatorAccountManager { case "PrysmValidatorService": { let walletPath = ""; if (typeof service.volumes[0] == "string") { - walletPath = ServiceVolume.buildByConfig( - service.volumes.find((v) => v.includes("/opt/app/data/wallets")) - ).destinationPath; + walletPath = ServiceVolume.buildByConfig(service.volumes.find((v) => v.includes("/opt/app/data/wallets"))).destinationPath; } else { walletPath = service.volumes.find((v) => v.servicePath == "/opt/app/data/wallets").destinationPath; } //Make sure keystores have correct permissions - const chmodResult = await this.nodeConnection.sshService.exec( - "chmod -Rv 600 " + walletPath + "/direct/accounts/*" - ); + const chmodResult = await this.nodeConnection.sshService.exec("chmod -Rv 600 " + walletPath + "/direct/accounts/*"); log.info(chmodResult.stdout); if (walletPath) { result = await this.nodeConnection.sshService.exec("cat " + walletPath + "/auth-token"); @@ -629,9 +573,7 @@ export class ValidatorAccountManager { ); break; case "Web3SignerService": - result = await this.nodeConnection.sshService.exec( - `docker exec stereum-${service.id} curl -X POST http://localhost:9000/reload` - ); + result = await this.nodeConnection.sshService.exec(`docker exec stereum-${service.id} curl -X POST http://localhost:9000/reload`); result.stdout = ""; break; } @@ -661,12 +603,7 @@ export class ValidatorAccountManager { } //Push successful task - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Get signed voluntary exit message`, - true, - JSON.stringify(data) - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Get signed voluntary exit message`, true, JSON.stringify(data)); this.nodeConnection.taskManager.otherTasksHandler(ref); return data; } catch (error) { @@ -693,10 +630,9 @@ export class ValidatorAccountManager { if (key.status === "duplicate") duplicate++; if (key.status === "error") error++; return ( - `${pubkeys[index].substring(0, 20)}...${pubkeys[index].substring( - pubkeys[index].length - 6, - pubkeys[index].length - )}:\t${key.status}` + (key.status == "error" ? `:\n${key.message}\n` : "") + `${pubkeys[index].substring(0, 20)}...${pubkeys[index].substring(pubkeys[index].length - 6, pubkeys[index].length)}:\t${ + key.status + }` + (key.status == "error" ? `:\n${key.message}\n` : "") ); }) .join("\n"); @@ -751,12 +687,7 @@ export class ValidatorAccountManager { this.nodeConnection.taskManager.otherTasksHandler(ref); return message; } catch (err) { - this.nodeConnection.taskManager.otherTasksHandler( - ref, - `Remote Import Failed`, - false, - "Remote Validator Import Failed:\n" + err - ); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Remote Import Failed`, false, "Remote Validator Import Failed:\n" + err); this.nodeConnection.taskManager.otherTasksHandler(ref); log.error("Remote Validator Import Failed:\n", err); return "Remote Validator Import Failed:\n" + err; @@ -1064,8 +995,7 @@ export class ValidatorAccountManager { if (!charonClient) throw "Couldn't find CharonService"; let contentResult = await this.nodeConnection.sshService.exec(charonClient.getListCharonFolderContentsCommand()); - if (SSHService.checkExecError(contentResult) && contentResult.stderr) - throw SSHService.extractExecError(contentResult); + if (SSHService.checkExecError(contentResult) && contentResult.stderr) throw SSHService.extractExecError(contentResult); const content = contentResult.stdout; const dkgCommand = charonClient.getDKGCommand( content.includes("cluster-definition.json") ? "" : input.match(/http(s)?:.*\/[0-9a-zA-z]*/)[0] diff --git a/launcher/src/backend/ethereum-services/BesuService.js b/launcher/src/backend/ethereum-services/BesuService.js index 64d6333f66..3d5f8bcc20 100755 --- a/launcher/src/backend/ethereum-services/BesuService.js +++ b/launcher/src/backend/ethereum-services/BesuService.js @@ -8,10 +8,7 @@ export class BesuService extends NodeService { const workingDir = service.buildWorkingDir(dir); const dataDir = "/opt/app/data"; const JWTDir = "/engine.jwt"; - const volumes = [ - new ServiceVolume(workingDir + "/data", "/opt/app/data"), - new ServiceVolume(workingDir + "/engine.jwt", JWTDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", "/opt/app/data"), new ServiceVolume(workingDir + "/engine.jwt", JWTDir)]; service.init( "BesuService", // service @@ -83,8 +80,7 @@ export class BesuService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${this.id}\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; } } diff --git a/launcher/src/backend/ethereum-services/CharonService.js b/launcher/src/backend/ethereum-services/CharonService.js index ff1061b706..5d0af7cab1 100755 --- a/launcher/src/backend/ethereum-services/CharonService.js +++ b/launcher/src/backend/ethereum-services/CharonService.js @@ -8,9 +8,7 @@ export class CharonService extends NodeService { const workingDir = service.buildWorkingDir(dir); const dataDir = "/opt/charon"; - const volumes = [ - new ServiceVolume(workingDir, dataDir), - ]; + const volumes = [new ServiceVolume(workingDir, dataDir)]; const beaconNodes = consensusClients .map((client) => { @@ -33,7 +31,7 @@ export class CharonService extends NodeService { "--p2p-tcp-address=0.0.0.0:3610", "--validator-api-address=0.0.0.0:3600", "--monitoring-address=0.0.0.0:3620", - "--builder-api" + "--builder-api", ], // command ["/usr/local/bin/charon"], // entrypoint null, // env @@ -42,23 +40,24 @@ export class CharonService extends NodeService { null, // user network, // network null, // executionClients - consensusClients // consensusClients + consensusClients // consensusClients ); - if (consensusClients.map(s => s.service).includes("NimbusBeaconService")) { - service.command.push("--feature-set-enable=json_requests") + if (consensusClients.map((s) => s.service).includes("NimbusBeaconService")) { + service.command.push("--feature-set-enable=json_requests"); } - if (consensusClients.map(s => s.service).includes("TekuBeaconService")) { - consensusClients.filter(s => s.service === "TekuBeaconService").forEach(s => { - s.command.push(`--validators-graffiti-client-append-format=DISABLED`) - }) + if (consensusClients.map((s) => s.service).includes("TekuBeaconService")) { + consensusClients + .filter((s) => s.service === "TekuBeaconService") + .forEach((s) => { + s.command.push(`--validators-graffiti-client-append-format=DISABLED`); + }); } return service; } - static buildByConfiguration(config) { const service = new CharonService(); @@ -79,7 +78,6 @@ export class CharonService extends NodeService { return "stereum-" + this.id + ":3600"; } - getDataDir() { return this.volumes.find((volume) => volume.servicePath === "/opt/charon").destinationPath; } @@ -105,20 +103,21 @@ export class CharonService extends NodeService { } getWriteENRPrivateKeyCommand(privateKey) { - return `echo "${privateKey}" > ${this.getDataDir()}/.charon/charon-enr-private-key` + return `echo "${privateKey}" > ${this.getDataDir()}/.charon/charon-enr-private-key`; } getReadENRPrivateKeyCommand() { - return `cat ${this.getDataDir()}/.charon/charon-enr-private-key` + return `cat ${this.getDataDir()}/.charon/charon-enr-private-key`; } getListCharonFolderContentsCommand() { - return `ls -1 -a ${this.getDataDir()}/.charon` + return `ls -1 -a ${this.getDataDir()}/.charon`; } //definitionFile as URL or Path to file (default ".charon/cluster-definition.json" by dkg command) getDKGCommand(definitionFile) { - return `docker run -u 0 --name "dkg-container" -d -v "${this.getDataDir()}:/opt/charon" ${this.image + ":" + this.imageVersion} dkg ${definitionFile ? "--definition-file=" + definitionFile : ""} --publish`; - + return `docker run -u 0 --name "dkg-container" -d -v "${this.getDataDir()}:/opt/charon" ${this.image + ":" + this.imageVersion} dkg ${ + definitionFile ? "--definition-file=" + definitionFile : "" + } --publish`; } } diff --git a/launcher/src/backend/ethereum-services/CustomService.js b/launcher/src/backend/ethereum-services/CustomService.js index e3bc2091ca..8871c12948 100644 --- a/launcher/src/backend/ethereum-services/CustomService.js +++ b/launcher/src/backend/ethereum-services/CustomService.js @@ -10,18 +10,18 @@ export class CustomService extends NodeService { const image = CustomService.parseImageString(imageString); - command = command.replace(/\s\s+/g, ' ').trim(); + command = command.replace(/\s\s+/g, " ").trim(); - const finalPorts = ports.map(p => { + const finalPorts = ports.map((p) => { return ServicePort.buildByConfig(p); }); - const finalVolumes = volumes.map(v => { + const finalVolumes = volumes.map((v) => { if (v.includes("")) { v = v.replace("", workingDir); } return ServiceVolume.buildByConfig(v); - }) + }); service.init( "CustomService", // service diff --git a/launcher/src/backend/ethereum-services/ErigonService.js b/launcher/src/backend/ethereum-services/ErigonService.js index 8f75e1d49c..bc064d8d65 100755 --- a/launcher/src/backend/ethereum-services/ErigonService.js +++ b/launcher/src/backend/ethereum-services/ErigonService.js @@ -9,10 +9,7 @@ export class ErigonService extends NodeService { const JWTDir = "/engine.jwt"; const dataDir = "/opt/data/erigon"; - const volumes = [ - new ServiceVolume(workingDir + "/data", dataDir), - new ServiceVolume(workingDir + "/engine.jwt", JWTDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", dataDir), new ServiceVolume(workingDir + "/engine.jwt", JWTDir)]; service.init( "ErigonService", // service @@ -28,7 +25,7 @@ export class ErigonService extends NodeService { `--authrpc.vhosts=*`, `--authrpc.port=8551`, `--authrpc.jwtsecret=/engine.jwt`, - '--rpc.returndata.limit=1000000', + "--rpc.returndata.limit=1000000", `--ws`, `--http`, `--http.vhosts=*`, @@ -39,8 +36,8 @@ export class ErigonService extends NodeService { `--metrics`, `--metrics.addr=0.0.0.0`, `--metrics.port=6060`, - '--db.pagesize=16K', - '--db.size.limit=8TB', + "--db.pagesize=16K", + "--db.size.limit=8TB", ], // command [], // entrypoint null, // env @@ -85,12 +82,12 @@ export class ErigonService extends NodeService { } switchImageTag(arch) { - const armArchs = ["arm", "arm64", "aarch64_be", "aarch64", "armv8b", "armv8l"] //Possible arm architectures: https://stackoverflow.com/questions/45125516/possible-values-for-uname-m + const armArchs = ["arm", "arm64", "aarch64_be", "aarch64", "armv8b", "armv8l"]; //Possible arm architectures: https://stackoverflow.com/questions/45125516/possible-values-for-uname-m if (armArchs.includes(arch)) { this.imageVersion = this.imageVersion.endsWith("-arm64") ? this.imageVersion : this.imageVersion + "-arm64"; this.imageVersion = this.imageVersion.startsWith("v") ? this.imageVersion.slice(1) : this.imageVersion; } else { - this.imageVersion = this.imageVersion.endsWith("-arm64") ? this.imageVersion.replace("-arm64", "") : this.imageVersion + this.imageVersion = this.imageVersion.endsWith("-arm64") ? this.imageVersion.replace("-arm64", "") : this.imageVersion; this.imageVersion = this.imageVersion.startsWith("v") ? this.imageVersion : "v" + this.imageVersion; } } @@ -116,8 +113,9 @@ export class ErigonService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n metrics_path: /debug/metrics/prometheus\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${ + this.id + }\n metrics_path: /debug/metrics/prometheus\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; } } diff --git a/launcher/src/backend/ethereum-services/ExternalExecutionService.js b/launcher/src/backend/ethereum-services/ExternalExecutionService.js index 14623cc128..328949728a 100644 --- a/launcher/src/backend/ethereum-services/ExternalExecutionService.js +++ b/launcher/src/backend/ethereum-services/ExternalExecutionService.js @@ -7,10 +7,7 @@ export class ExternalExecutionService extends NodeService { service.setId(); const workingDir = service.buildWorkingDir(dir); - const volumes = [ - new ServiceVolume(workingDir + "/link.txt", ""), - new ServiceVolume(workingDir + "/engine.jwt", ""), - ]; + const volumes = [new ServiceVolume(workingDir + "/link.txt", ""), new ServiceVolume(workingDir + "/engine.jwt", "")]; service.init( "ExternalExecutionService", // service diff --git a/launcher/src/backend/ethereum-services/GethService.js b/launcher/src/backend/ethereum-services/GethService.js index 37ba5e8cd3..b940268a80 100755 --- a/launcher/src/backend/ethereum-services/GethService.js +++ b/launcher/src/backend/ethereum-services/GethService.js @@ -9,10 +9,7 @@ export class GethService extends NodeService { const JWTDir = "/engine.jwt"; const dataDir = "/opt/data/geth"; - const volumes = [ - new ServiceVolume(workingDir + "/data", dataDir), - new ServiceVolume(workingDir + "/engine.jwt", JWTDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", dataDir), new ServiceVolume(workingDir + "/engine.jwt", JWTDir)]; service.init( "GethService", // service diff --git a/launcher/src/backend/ethereum-services/KuboIPFSService.js b/launcher/src/backend/ethereum-services/KuboIPFSService.js index b1b4d7b6a5..ad1bafe98d 100644 --- a/launcher/src/backend/ethereum-services/KuboIPFSService.js +++ b/launcher/src/backend/ethereum-services/KuboIPFSService.js @@ -12,10 +12,7 @@ export class KuboIPFSService extends NodeService { const dataDir = "/data/ipfs"; const exportDir = "/export"; - const volumes = [ - new ServiceVolume(workingDir + dataDir, dataDir), - new ServiceVolume(workingDir + exportDir, exportDir), - ]; + const volumes = [new ServiceVolume(workingDir + dataDir, dataDir), new ServiceVolume(workingDir + exportDir, exportDir)]; service.init( "KuboIPFSService", //service diff --git a/launcher/src/backend/ethereum-services/LCOMService.js b/launcher/src/backend/ethereum-services/LCOMService.js index 934f240f43..848aece27b 100644 --- a/launcher/src/backend/ethereum-services/LCOMService.js +++ b/launcher/src/backend/ethereum-services/LCOMService.js @@ -25,9 +25,7 @@ export class LCOMService extends NodeService { ["python", "main.py"], // entrypoint { RPC_API: executionClients[0] ? executionClients[0].buildExecutionClientHttpEndpointUrl() : "http://RPC-api", - BEACON_API: consensusClients[0] - ? consensusClients[0].buildConsensusClientHttpEndpointUrl() - : "http://beacon-api", + BEACON_API: consensusClients[0] ? consensusClients[0].buildConsensusClientHttpEndpointUrl() : "http://beacon-api", IPFS_API: ipfs ? ipfs.buildIPFSHttpEndpointUrl() : "http://IPFS-api", NO_ID: "123456", LOG_LEVEL: "INFO", diff --git a/launcher/src/backend/ethereum-services/LidoObolExitService.js b/launcher/src/backend/ethereum-services/LidoObolExitService.js index 95b1c278a0..ac07b9aeac 100644 --- a/launcher/src/backend/ethereum-services/LidoObolExitService.js +++ b/launcher/src/backend/ethereum-services/LidoObolExitService.js @@ -3,11 +3,9 @@ import { ServiceVolume } from "./ServiceVolume"; export class LidoObolExitService extends NodeService { static buildByUserInput(network, ports, dir, consensusClients, otherServices) { - let ejector = otherServices.find((service) => service.service === "ValidatorEjectorService"); let charon = consensusClients.find((service) => service.service === "CharonService"); - if (charon) - otherServices.push(charon); + if (charon) otherServices.push(charon); consensusClients = consensusClients.filter((service) => !(service.service === "CharonService")); const service = new LidoObolExitService(); @@ -19,19 +17,12 @@ export class LidoObolExitService extends NodeService { const exitmessagesDir = "/exitmessages"; const charonDir = "/charon"; - const charonFoler = charon ? `${charon.getDataDir()}/.charon` : workingDir + "/charon"; - let messageVolume = ejector ? ejector.volumes.find((volume) => volume.servicePath === '/app/messages') : ""; + let messageVolume = ejector ? ejector.volumes.find((volume) => volume.servicePath === "/app/messages") : ""; const messageDir = messageVolume ? messageVolume.destinationPath : workingDir + "/exitmessages"; - const volumes = [ - new ServiceVolume(messageDir, exitmessagesDir), - new ServiceVolume(charonFoler, charonDir), - ]; - - - + const volumes = [new ServiceVolume(messageDir, exitmessagesDir), new ServiceVolume(charonFoler, charonDir)]; service.init( "LidoObolExitService", //service @@ -49,7 +40,7 @@ export class LidoObolExitService extends NodeService { "--log-format=console", "--log-level=info", "--obol-api-url=https://api.obol.tech", - "--validator-query-chunk-size=50" + "--validator-query-chunk-size=50", ], // command ["/usr/local/bin/lido-dv-exit"], // entrypoint null, // env diff --git a/launcher/src/backend/ethereum-services/LighthouseBeaconService.js b/launcher/src/backend/ethereum-services/LighthouseBeaconService.js index 48467aefba..202224e4af 100755 --- a/launcher/src/backend/ethereum-services/LighthouseBeaconService.js +++ b/launcher/src/backend/ethereum-services/LighthouseBeaconService.js @@ -14,10 +14,7 @@ export class LighthouseBeaconService extends NodeService { const slasherDir = "/opt/app/slasher"; // volumes - const volumes = [ - new ServiceVolume(workingDir + "/beacon", dataDir), - new ServiceVolume(workingDir + "/slasher", slasherDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/beacon", dataDir), new ServiceVolume(workingDir + "/slasher", slasherDir)]; // eth1 nodes const eth1Nodes = executionClients @@ -110,8 +107,7 @@ export class LighthouseBeaconService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n static_configs:\n - targets: [${this.buildConsensusClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${this.id}\n static_configs:\n - targets: [${this.buildConsensusClientMetricsEndpoint()}]`; } getAvailablePorts() { diff --git a/launcher/src/backend/ethereum-services/LighthouseValidatorService.js b/launcher/src/backend/ethereum-services/LighthouseValidatorService.js index 8be8ce760e..b390263e33 100755 --- a/launcher/src/backend/ethereum-services/LighthouseValidatorService.js +++ b/launcher/src/backend/ethereum-services/LighthouseValidatorService.js @@ -13,10 +13,7 @@ export class LighthouseValidatorService extends NodeService { const dataDir = "/opt/app/validator"; const graffitiDir = "/opt/app/graffitis"; - const volumes = [ - new ServiceVolume(workingDir + "/validator", dataDir), - new ServiceVolume(workingDir + "/graffitis", graffitiDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/validator", dataDir), new ServiceVolume(workingDir + "/graffitis", graffitiDir)]; const eth2Nodes = consensusClients .map((client) => { @@ -60,8 +57,8 @@ export class LighthouseValidatorService extends NodeService { consensusClients //consensusClients ); - if (consensusClients.some(c => c.service === "CharonService")) { - service.command = service.command.filter(c => c !== "--enable-doppelganger-protection"); + if (consensusClients.some((c) => c.service === "CharonService")) { + service.command = service.command.filter((c) => c !== "--enable-doppelganger-protection"); } return service; diff --git a/launcher/src/backend/ethereum-services/LodestarValidatorService.js b/launcher/src/backend/ethereum-services/LodestarValidatorService.js index 2ed1dcf7be..662d7d6b0a 100755 --- a/launcher/src/backend/ethereum-services/LodestarValidatorService.js +++ b/launcher/src/backend/ethereum-services/LodestarValidatorService.js @@ -52,10 +52,10 @@ export class LodestarValidatorService extends NodeService { consensusClients //consensusClients ); - if (consensusClients.some(c => c.service === "CharonService")) { - service.command.push("--distributed") - service.command[service.command.findIndex(c => c === "--doppelgangerProtection=true")] = "--doppelgangerProtection=false" - service.command.push("--builder.selection=builderalways") + if (consensusClients.some((c) => c.service === "CharonService")) { + service.command.push("--distributed"); + service.command[service.command.findIndex((c) => c === "--doppelgangerProtection=true")] = "--doppelgangerProtection=false"; + service.command.push("--builder.selection=builderalways"); } return service; diff --git a/launcher/src/backend/ethereum-services/MetricsExporterService.js b/launcher/src/backend/ethereum-services/MetricsExporterService.js index 2ea30477e7..61458c50bd 100644 --- a/launcher/src/backend/ethereum-services/MetricsExporterService.js +++ b/launcher/src/backend/ethereum-services/MetricsExporterService.js @@ -38,7 +38,7 @@ export class MetricsExporterService extends NodeService { return service; } - static buildByConfiguration(config) { + static buildByConfiguration(config) { const service = new MetricsExporterService(); service.initByConfig(config); diff --git a/launcher/src/backend/ethereum-services/NethermindService.js b/launcher/src/backend/ethereum-services/NethermindService.js index 3f4da44a15..1605b61d6a 100755 --- a/launcher/src/backend/ethereum-services/NethermindService.js +++ b/launcher/src/backend/ethereum-services/NethermindService.js @@ -9,10 +9,7 @@ export class NethermindService extends NodeService { const dataDir = "/opt/app/data"; const JWTDir = "/engine.jwt"; - const volumes = [ - new ServiceVolume(workingDir + "/data", dataDir), - new ServiceVolume(workingDir + "/engine.jwt", JWTDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", dataDir), new ServiceVolume(workingDir + "/engine.jwt", JWTDir)]; service.init( "NethermindService", // service @@ -83,7 +80,6 @@ export class NethermindService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${this.id}\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; } } diff --git a/launcher/src/backend/ethereum-services/NimbusValidatorService.js b/launcher/src/backend/ethereum-services/NimbusValidatorService.js index 933d07b202..e6b934b21e 100755 --- a/launcher/src/backend/ethereum-services/NimbusValidatorService.js +++ b/launcher/src/backend/ethereum-services/NimbusValidatorService.js @@ -58,8 +58,8 @@ export class NimbusValidatorService extends NodeService { consensusClients //consensusClients ); - if (consensusClients.some(c => c.service === "CharonService")) { - service.command[service.command.findIndex(c => c === "--doppelganger-detection=true")] = "--doppelganger-detection=false" + if (consensusClients.some((c) => c.service === "CharonService")) { + service.command[service.command.findIndex((c) => c === "--doppelganger-detection=true")] = "--doppelganger-detection=false"; } return service; @@ -78,9 +78,6 @@ export class NimbusValidatorService extends NodeService { } getAvailablePorts() { - return [ - new ServicePortDefinition(8108, "tcp", "Metrics Port"), - new ServicePortDefinition(5052, "tcp", "Keymanager Port"), - ]; + return [new ServicePortDefinition(8108, "tcp", "Metrics Port"), new ServicePortDefinition(5052, "tcp", "Keymanager Port")]; } } diff --git a/launcher/src/backend/ethereum-services/NodeService.js b/launcher/src/backend/ethereum-services/NodeService.js index e86567a3b4..d460eee449 100755 --- a/launcher/src/backend/ethereum-services/NodeService.js +++ b/launcher/src/backend/ethereum-services/NodeService.js @@ -63,7 +63,7 @@ export class NodeService { executionClients, consensusClients, mevboost, - otherServices, + otherServices ) { this.service = service; this.setId(id); @@ -135,12 +135,8 @@ export class NodeService { network: this.network, dependencies: { - executionClients: (this.dependencies.executionClients || []).map((service) => - service.buildMinimalConfiguration() - ), - consensusClients: (this.dependencies.consensusClients || []).map((service) => - service.buildMinimalConfiguration() - ), + executionClients: (this.dependencies.executionClients || []).map((service) => service.buildMinimalConfiguration()), + consensusClients: (this.dependencies.consensusClients || []).map((service) => service.buildMinimalConfiguration()), mevboost: (this.dependencies.mevboost || []).map((service) => service.buildMinimalConfiguration()), otherServices: (this.dependencies.otherServices || []).map((service) => service.buildMinimalConfiguration()), }, diff --git a/launcher/src/backend/ethereum-services/PrometheusNodeExporterService.js b/launcher/src/backend/ethereum-services/PrometheusNodeExporterService.js index 26f5aea26c..c87a8b1679 100755 --- a/launcher/src/backend/ethereum-services/PrometheusNodeExporterService.js +++ b/launcher/src/backend/ethereum-services/PrometheusNodeExporterService.js @@ -42,7 +42,8 @@ export class PrometheusNodeExporterService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n static_configs:\n - targets: [${this.buildPrometheusNodeExporterClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${ + this.id + }\n static_configs:\n - targets: [${this.buildPrometheusNodeExporterClientMetricsEndpoint()}]`; } } diff --git a/launcher/src/backend/ethereum-services/PrometheusService.js b/launcher/src/backend/ethereum-services/PrometheusService.js index 478e8c3168..94e4d868fb 100755 --- a/launcher/src/backend/ethereum-services/PrometheusService.js +++ b/launcher/src/backend/ethereum-services/PrometheusService.js @@ -13,10 +13,7 @@ export class PrometheusService extends NodeService { const dataDir = "/prometheus"; const configDir = "/etc/prometheus"; - const volumes = [ - new ServiceVolume(workingDir + "/data/prometheus", dataDir), - new ServiceVolume(workingDir + "/config", configDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data/prometheus", dataDir), new ServiceVolume(workingDir + "/config", configDir)]; service.init( "PrometheusService", diff --git a/launcher/src/backend/ethereum-services/PrysmBeaconService.js b/launcher/src/backend/ethereum-services/PrysmBeaconService.js index 01c16a6629..c46138c14e 100755 --- a/launcher/src/backend/ethereum-services/PrysmBeaconService.js +++ b/launcher/src/backend/ethereum-services/PrysmBeaconService.js @@ -15,10 +15,7 @@ export class PrysmBeaconService extends NodeService { const genesisDir = "/opt/app/genesis"; //volumes - const volumes = [ - new ServiceVolume(workingDir + "/beacon", dataDir), - new ServiceVolume(workingDir + "/genesis", genesisDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/beacon", dataDir), new ServiceVolume(workingDir + "/genesis", genesisDir)]; //execution endpoint const executionEndpoint = executionClients @@ -59,7 +56,7 @@ export class PrysmBeaconService extends NodeService { "--p2p-tcp-port=13001", "--p2p-udp-port=12001", ], //command - ['/app/cmd/beacon-chain/beacon-chain'], //entrypoint + ["/app/cmd/beacon-chain/beacon-chain"], //entrypoint null, //env ports, //ports volumes, //volumes @@ -71,15 +68,15 @@ export class PrysmBeaconService extends NodeService { ); if (network == "holesky" || network == "sepolia") { - service.command.push(`--genesis-state=/opt/app/genesis/prysm-${network}-genesis.ssz`) + service.command.push(`--genesis-state=/opt/app/genesis/prysm-${network}-genesis.ssz`); } if (checkpointURL) { - service.command.push(`--checkpoint-sync-url=${checkpointURL}`) + service.command.push(`--checkpoint-sync-url=${checkpointURL}`); } if (mevboostEndpoint) { - service.command.push(`--http-mev-relay=${mevboostEndpoint}`) + service.command.push(`--http-mev-relay=${mevboostEndpoint}`); } return service; @@ -110,8 +107,7 @@ export class PrysmBeaconService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n static_configs:\n - targets: [${this.buildConsensusClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${this.id}\n static_configs:\n - targets: [${this.buildConsensusClientMetricsEndpoint()}]`; } getAvailablePorts() { diff --git a/launcher/src/backend/ethereum-services/PrysmValidatorService.js b/launcher/src/backend/ethereum-services/PrysmValidatorService.js index 94828f4a14..2373cf0133 100755 --- a/launcher/src/backend/ethereum-services/PrysmValidatorService.js +++ b/launcher/src/backend/ethereum-services/PrysmValidatorService.js @@ -40,27 +40,27 @@ export class PrysmValidatorService extends NodeService { image, //image "v5.1.0", //imageVersion [ - '--accept-terms-of-use=true', + "--accept-terms-of-use=true", `--beacon-rpc-provider=${provider}`, `--beacon-rpc-gateway-provider=${providerGateway}`, - '--web', + "--web", `--${network}`, `--datadir=${dataDir}`, `--keymanager-token-file=${walletDir + "/auth-token"}`, `--wallet-dir=${walletDir}`, `--wallet-password-file=${passwordDir + "/wallet-password"}`, - '--monitoring-host=0.0.0.0', - '--grpc-gateway-port=7500', - '--grpc-gateway-host=0.0.0.0', + "--monitoring-host=0.0.0.0", + "--grpc-gateway-port=7500", + "--grpc-gateway-host=0.0.0.0", '--grpc-gateway-corsdomain="*"', - '--monitoring-host=0.0.0.0', - '--monitoring-port=8081', - '--suggested-fee-recipient=0x0000000000000000000000000000000000000000', + "--monitoring-host=0.0.0.0", + "--monitoring-port=8081", + "--suggested-fee-recipient=0x0000000000000000000000000000000000000000", `--graffiti-file=${graffitiDir + "/graffitis.yaml"}`, - '--enable-builder=true', - '--enable-doppelganger=true', + "--enable-builder=true", + "--enable-doppelganger=true", ], //command - ['/app/cmd/validator/validator'], // entrypoint + ["/app/cmd/validator/validator"], // entrypoint null, // env ports, //ports volumes, //volumes diff --git a/launcher/src/backend/ethereum-services/RethService.js b/launcher/src/backend/ethereum-services/RethService.js index aa8c6d664b..9894e99968 100644 --- a/launcher/src/backend/ethereum-services/RethService.js +++ b/launcher/src/backend/ethereum-services/RethService.js @@ -8,10 +8,7 @@ export class RethService extends NodeService { const workingDir = service.buildWorkingDir(dir); const dataDir = "/opt/data/reth"; const JWTDir = "/engine.jwt"; - const volumes = [ - new ServiceVolume(workingDir + "/data", dataDir), - new ServiceVolume(workingDir + "/engine.jwt", JWTDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", dataDir), new ServiceVolume(workingDir + "/engine.jwt", JWTDir)]; service.init( "RethService", // service @@ -26,12 +23,12 @@ export class RethService extends NodeService { "--http", "--http.port=8545", "--http.addr=0.0.0.0", - '--http.api=debug,web3,eth,net', + "--http.api=debug,web3,eth,net", "--http.corsdomain=*", "--ws", "--ws.port=8546", "--ws.addr=0.0.0.0", - '--ws.api=debug,web3,eth,net', + "--ws.api=debug,web3,eth,net", "--ws.origins=*", "--authrpc.port=8551", "--authrpc.addr=0.0.0.0", @@ -80,8 +77,7 @@ export class RethService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${this.id}\n static_configs:\n - targets: [${this.buildExecutionClientMetricsEndpoint()}]`; } } diff --git a/launcher/src/backend/ethereum-services/SSVDKGService.js b/launcher/src/backend/ethereum-services/SSVDKGService.js index f4b4afe0a0..f47706a1ac 100644 --- a/launcher/src/backend/ethereum-services/SSVDKGService.js +++ b/launcher/src/backend/ethereum-services/SSVDKGService.js @@ -25,10 +25,7 @@ outputPath: /data/output`; // Note that local secrets volume will be replaced with // shared volume from SSVNetworkService later on... - const volumes = [ - new ServiceVolume(workingDir + "/data", "/data"), - new ServiceVolume(workingDir + "/secrets", "/secrets"), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", "/data"), new ServiceVolume(workingDir + "/secrets", "/secrets")]; console.log("-------> TTT :: otherServices", otherServices); @@ -64,10 +61,7 @@ outputPath: /data/output`; } getAvailablePorts() { - return [ - new ServicePortDefinition(3030, "tcp", "TCP connections"), - new ServicePortDefinition(3030, "udp", "UDP connections"), - ]; + return [new ServicePortDefinition(3030, "tcp", "TCP connections"), new ServicePortDefinition(3030, "udp", "UDP connections")]; } } diff --git a/launcher/src/backend/ethereum-services/SSVNetworkService.js b/launcher/src/backend/ethereum-services/SSVNetworkService.js index 90a2038ed4..5945caf776 100755 --- a/launcher/src/backend/ethereum-services/SSVNetworkService.js +++ b/launcher/src/backend/ethereum-services/SSVNetworkService.js @@ -53,10 +53,7 @@ MetricsAPIPort: 15000`; const image = "bloxstaking/ssv-node"; - const volumes = [ - new ServiceVolume(workingDir + "/data", "/data"), - new ServiceVolume(workingDir + "/secrets", "/secrets"), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", "/data"), new ServiceVolume(workingDir + "/secrets", "/secrets")]; // build service service.init( diff --git a/launcher/src/backend/ethereum-services/ServicePort.js b/launcher/src/backend/ethereum-services/ServicePort.js index 8a923faa53..47a4bf4e42 100755 --- a/launcher/src/backend/ethereum-services/ServicePort.js +++ b/launcher/src/backend/ethereum-services/ServicePort.js @@ -49,7 +49,6 @@ export class ServicePort { const servicePort = servicePortSettings?.length >= 1 ? servicePortSettings[0] : ""; const servicePortProtocol = servicePortSettings?.length >= 2 ? servicePortSettings[1] : ""; - return new ServicePort(destinationIp, destinationPort, servicePort, servicePortProtocol); } diff --git a/launcher/src/backend/ethereum-services/TekuBeaconService.js b/launcher/src/backend/ethereum-services/TekuBeaconService.js index 44c8868a32..ca7b1c7d3a 100755 --- a/launcher/src/backend/ethereum-services/TekuBeaconService.js +++ b/launcher/src/backend/ethereum-services/TekuBeaconService.js @@ -104,8 +104,9 @@ export class TekuBeaconService extends NodeService { } buildPrometheusJob() { - return `\n - job_name: stereum-${this.id - }\n scrape_timeout: 10s\n metrics_path: /metrics\n scheme: http\n static_configs:\n - targets: [${this.buildConsensusClientMetricsEndpoint()}]`; + return `\n - job_name: stereum-${ + this.id + }\n scrape_timeout: 10s\n metrics_path: /metrics\n scheme: http\n static_configs:\n - targets: [${this.buildConsensusClientMetricsEndpoint()}]`; } getAvailablePorts() { diff --git a/launcher/src/backend/ethereum-services/TekuValidatorService.js b/launcher/src/backend/ethereum-services/TekuValidatorService.js index a585586b67..087050c791 100755 --- a/launcher/src/backend/ethereum-services/TekuValidatorService.js +++ b/launcher/src/backend/ethereum-services/TekuValidatorService.js @@ -19,10 +19,7 @@ export class TekuValidatorService extends NodeService { const dataDir = "/opt/app/data"; const graffitiDir = "/opt/app/graffitis"; - const volumes = [ - new ServiceVolume(workingDir + "/data", dataDir), - new ServiceVolume(workingDir + "/graffitis", graffitiDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", dataDir), new ServiceVolume(workingDir + "/graffitis", graffitiDir)]; service.init( "TekuValidatorService", // service @@ -65,8 +62,9 @@ export class TekuValidatorService extends NodeService { consensusClients //consensusClients ); - if (consensusClients.some(c => c.service === "CharonService")) { - service.command[service.command.findIndex(c => c === "--doppelganger-detection-enabled=true")] = "--doppelganger-detection-enabled=false" + if (consensusClients.some((c) => c.service === "CharonService")) { + service.command[service.command.findIndex((c) => c === "--doppelganger-detection-enabled=true")] = + "--doppelganger-detection-enabled=false"; } return service; diff --git a/launcher/src/backend/ethereum-services/Web3SignerService.js b/launcher/src/backend/ethereum-services/Web3SignerService.js index 2ada032bb7..bdaa8602fe 100755 --- a/launcher/src/backend/ethereum-services/Web3SignerService.js +++ b/launcher/src/backend/ethereum-services/Web3SignerService.js @@ -13,10 +13,7 @@ export class Web3SignerService extends NodeService { const dataDir = "/opt/web3signer/data"; const keysDir = "/opt/web3signer/keys"; - const volumes = [ - new ServiceVolume(workingDir + "/data", dataDir), - new ServiceVolume(workingDir + "/keys", keysDir), - ]; + const volumes = [new ServiceVolume(workingDir + "/data", dataDir), new ServiceVolume(workingDir + "/keys", keysDir)]; service.init( "Web3SignerService", // service @@ -75,10 +72,7 @@ export class Web3SignerService extends NodeService { } getAvailablePorts() { - return [ - new ServicePortDefinition(9000, "tcp", "REST API Port"), - new ServicePortDefinition(9001, "tcp", "METRICS Port"), - ]; + return [new ServicePortDefinition(9000, "tcp", "REST API Port"), new ServicePortDefinition(9001, "tcp", "METRICS Port")]; } } diff --git a/launcher/src/backend/tests/integration/BesuService.int.js b/launcher/src/backend/tests/integration/BesuService.int.js index 5e9070ac61..8c56c26da1 100755 --- a/launcher/src/backend/tests/integration/BesuService.int.js +++ b/launcher/src/backend/tests/integration/BesuService.int.js @@ -11,16 +11,14 @@ jest.setTimeout(500000); test("besu installation", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Besu--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Besu--integration-test--ubuntu-2204"); const serverSettings = { name: "Besu--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx21", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -38,7 +36,7 @@ test("besu installation", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,7 +53,7 @@ test("besu installation", async () => { await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); //install besu - let executionClient = serviceManager.getService("BesuService", { network: "holesky", installDir: "/opt/stereum" }) + let executionClient = serviceManager.getService("BesuService", { network: "holesky", installDir: "/opt/stereum" }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); executionClient.imageVersion = versions[executionClient.network][executionClient.service].slice(-1).pop(); @@ -89,7 +87,7 @@ test("besu installation", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/30303\/tcp/); diff --git a/launcher/src/backend/tests/integration/ErigonService.int.js b/launcher/src/backend/tests/integration/ErigonService.int.js index f84d1c5ffe..3e130e2e36 100755 --- a/launcher/src/backend/tests/integration/ErigonService.int.js +++ b/launcher/src/backend/tests/integration/ErigonService.int.js @@ -11,16 +11,14 @@ jest.setTimeout(500000); test("erigon installation", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Erigon--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Erigon--integration-test--ubuntu-2204"); const serverSettings = { name: "Erigon--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx21", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -38,7 +36,7 @@ test("erigon installation", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,7 +53,7 @@ test("erigon installation", async () => { await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); //install erigon - let executionClient = serviceManager.getService("ErigonService", { network: "holesky", installDir: "/opt/stereum" }) + let executionClient = serviceManager.getService("ErigonService", { network: "holesky", installDir: "/opt/stereum" }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); executionClient.imageVersion = versions[executionClient.network][executionClient.service].slice(-1).pop(); @@ -85,7 +83,7 @@ test("erigon installation", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/30303\/tcp/); diff --git a/launcher/src/backend/tests/integration/FlashbotsMevBoostService.int.js b/launcher/src/backend/tests/integration/FlashbotsMevBoostService.int.js index 49514568b4..8a5b9b15c2 100755 --- a/launcher/src/backend/tests/integration/FlashbotsMevBoostService.int.js +++ b/launcher/src/backend/tests/integration/FlashbotsMevBoostService.int.js @@ -11,16 +11,14 @@ jest.setTimeout(600000); test("mevboost installation", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Mevboost--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Mevboost--integration-test--ubuntu-2204"); const serverSettings = { name: "Mevboost--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx21", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -38,7 +36,7 @@ test("mevboost installation", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,7 +53,11 @@ test("mevboost installation", async () => { await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); //install mevboost - let mevboost = serviceManager.getService("FlashbotsMevBoostService", { network: "holesky", relays: "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net" }) + let mevboost = serviceManager.getService("FlashbotsMevBoostService", { + network: "holesky", + relays: + "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net", + }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); mevboost.imageVersion = versions[mevboost.network][mevboost.service].slice(-1).pop(); @@ -82,7 +84,7 @@ test("mevboost installation", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check docker container expect(docker.stdout).toMatch(/flashbots\/mev-boost/); diff --git a/launcher/src/backend/tests/integration/GethService.int.js b/launcher/src/backend/tests/integration/GethService.int.js index 9321452cab..36d2fb12c2 100755 --- a/launcher/src/backend/tests/integration/GethService.int.js +++ b/launcher/src/backend/tests/integration/GethService.int.js @@ -11,16 +11,14 @@ jest.setTimeout(500000); test("geth installation", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Geth--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Geth--integration-test--ubuntu-2204"); const serverSettings = { name: "Geth--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx21", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -38,7 +36,7 @@ test("geth installation", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,7 +53,7 @@ test("geth installation", async () => { await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); //install geth - let executionClient = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }) + let executionClient = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); executionClient.imageVersion = versions[executionClient.network][executionClient.service].slice(-1).pop(); @@ -86,7 +84,7 @@ test("geth installation", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/30303\/tcp/); @@ -107,5 +105,4 @@ test("geth installation", async () => { expect(status.stderr).toMatch(/Loaded JWT secret file/); expect(status.stderr).toMatch(/Looking for peers/); expect(status.stderr).toMatch(/HTTP server started/); - }); diff --git a/launcher/src/backend/tests/integration/LighthouseBeaconService.int.js b/launcher/src/backend/tests/integration/LighthouseBeaconService.int.js index 0814a8da9f..f0b7434980 100755 --- a/launcher/src/backend/tests/integration/LighthouseBeaconService.int.js +++ b/launcher/src/backend/tests/integration/LighthouseBeaconService.int.js @@ -12,16 +12,14 @@ jest.setTimeout(1000000); test("lighthouse validator import", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Lighthouse--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Lighthouse--integration-test--ubuntu-2204"); const serverSettings = { name: "Lighthouse--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx31", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -39,7 +37,7 @@ test("lighthouse validator import", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,22 +53,27 @@ test("lighthouse validator import", async () => { await nodeConnection.findStereumSettings(); await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); - let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }) - + let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }); - let lhBC = serviceManager.getService("LighthouseBeaconService", { network: "holesky", installDir: "/opt/stereum", executionClients: [geth] }) + let lhBC = serviceManager.getService("LighthouseBeaconService", { + network: "holesky", + installDir: "/opt/stereum", + executionClients: [geth], + }); - - let lhVC = serviceManager.getService("LighthouseValidatorService", { network: "holesky", installDir: "/opt/stereum", consensusClients: [lhBC] }) + let lhVC = serviceManager.getService("LighthouseValidatorService", { + network: "holesky", + installDir: "/opt/stereum", + consensusClients: [lhBC], + }); //get latest versions let versions = await nodeConnection.nodeUpdates.checkUpdates(); geth.imageVersion = versions[geth.network][geth.service].slice(-1).pop(); - lhBC.imageVersion = versions[lhBC.network][lhBC.service].slice(-1).pop() - lhVC.imageVersion = versions[lhVC.network][lhVC.service].slice(-1).pop() + lhBC.imageVersion = versions[lhBC.network][lhBC.service].slice(-1).pop(); + lhVC.imageVersion = versions[lhVC.network][lhVC.service].slice(-1).pop(); - await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()), - await serviceManager.manageServiceState(geth.id, "started"); + await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()), await serviceManager.manageServiceState(geth.id, "started"); //write configs for lighhouse BC and VC await nodeConnection.writeServiceConfiguration(lhBC.buildConfiguration()); @@ -92,7 +95,7 @@ test("lighthouse validator import", async () => { '{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "fa52987837af01ec48e2b21f2078acef3368983943751013758052e07dae841d"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "8c055c8c504cd3ad20bcb1101431b2b1a506b1a4d0efdbd294d75c39c0f2268b"}}, "description": "", "pubkey": "948f092cb5b5cae121fdc14af0e4e5a90d03ab661266b700ded1c1ca4fd6f0a76f8dac187815409197bf036675571458", "path": "m/12381/3600/2/0/0", "uuid": "c7521eed-533a-4fd1-90b7-ad1aa0f24a2d", "version": 4}', ], passwords: ["MyTestPassword", "MyTestPassword", "MyTestPassword"], - }) + }); await validatorAccountManager.importKey(lhVC.id); //get logs @@ -127,12 +130,10 @@ test("lighthouse validator import", async () => { const ufw = await nodeConnection.sshService.exec("ufw status"); const docker = await nodeConnection.sshService.exec("docker ps"); - const api_token = await nodeConnection.sshService.exec( - `cat /opt/stereum/lighthouse-${lhVC.id}/validator/validators/api-token.txt` - ); + const api_token = await nodeConnection.sshService.exec(`cat /opt/stereum/lighthouse-${lhVC.id}/validator/validators/api-token.txt`); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/9000\/tcp/); @@ -169,5 +170,4 @@ test("lighthouse validator import", async () => { expect(VCstatus.stderr).toMatch(/HTTP API started/); expect(VCstatus.stderr).toMatch(/Importing keystores via standard HTTP API, count: 3/); expect(VCstatus.stderr).toMatch(/Enabled validator/); - }); diff --git a/launcher/src/backend/tests/integration/LodestarBeaconService.int.js b/launcher/src/backend/tests/integration/LodestarBeaconService.int.js index 4bced3d6f2..95fab45a96 100755 --- a/launcher/src/backend/tests/integration/LodestarBeaconService.int.js +++ b/launcher/src/backend/tests/integration/LodestarBeaconService.int.js @@ -13,16 +13,14 @@ jest.setTimeout(1000000); test("lodestar validator import", async () => { //create server const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Lodestar--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Lodestar--integration-test--ubuntu-2204"); const serverSettings = { name: "Lodestar--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx31", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -40,7 +38,7 @@ test("lodestar validator import", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -56,20 +54,27 @@ test("lodestar validator import", async () => { await nodeConnection.findStereumSettings(); await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); - let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }) + let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }); - let lBC = serviceManager.getService("LodestarBeaconService", { network: "holesky", installDir: "/opt/stereum", executionClients: [geth] }); + let lBC = serviceManager.getService("LodestarBeaconService", { + network: "holesky", + installDir: "/opt/stereum", + executionClients: [geth], + }); - let lVC = serviceManager.getService("LodestarValidatorService", { network: "holesky", installDir: "/opt/stereum", consensusClients: [lBC] }); + let lVC = serviceManager.getService("LodestarValidatorService", { + network: "holesky", + installDir: "/opt/stereum", + consensusClients: [lBC], + }); //get latest versions let versions = await nodeConnection.nodeUpdates.checkUpdates(); geth.imageVersion = versions[geth.network][geth.service].slice(-1).pop(); - lBC.imageVersion = versions[lBC.network][lBC.service].slice(-1).pop() - lVC.imageVersion = versions[lVC.network][lVC.service].slice(-1).pop() + lBC.imageVersion = versions[lBC.network][lBC.service].slice(-1).pop(); + lVC.imageVersion = versions[lVC.network][lVC.service].slice(-1).pop(); - await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()), - await serviceManager.manageServiceState(geth.id, "started"); + await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()), await serviceManager.manageServiceState(geth.id, "started"); //write configs for lodestar BC and VC await nodeConnection.writeServiceConfiguration(lBC.buildConfiguration()); @@ -91,7 +96,7 @@ test("lodestar validator import", async () => { '{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "fa52987837af01ec48e2b21f2078acef3368983943751013758052e07dae841d"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "8c055c8c504cd3ad20bcb1101431b2b1a506b1a4d0efdbd294d75c39c0f2268b"}}, "description": "", "pubkey": "948f092cb5b5cae121fdc14af0e4e5a90d03ab661266b700ded1c1ca4fd6f0a76f8dac187815409197bf036675571458", "path": "m/12381/3600/2/0/0", "uuid": "c7521eed-533a-4fd1-90b7-ad1aa0f24a2d", "version": 4}', ], passwords: ["MyTestPassword", "MyTestPassword", "MyTestPassword"], - }) + }); await validatorAccountManager.importKey(lVC.id); //get logs @@ -119,12 +124,10 @@ test("lodestar validator import", async () => { const ufw = await nodeConnection.sshService.exec("ufw status"); const docker = await nodeConnection.sshService.exec("docker ps"); - const api_token = await nodeConnection.sshService.exec( - `cat /opt/stereum/lodestar-${lVC.id}/validator/validator-db/api-token.txt` - ); + const api_token = await nodeConnection.sshService.exec(`cat /opt/stereum/lodestar-${lVC.id}/validator/validator-db/api-token.txt`); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/30303\/tcp/); diff --git a/launcher/src/backend/tests/integration/NethermindService.int.js b/launcher/src/backend/tests/integration/NethermindService.int.js index a1b1bdbce4..b5bb170c95 100755 --- a/launcher/src/backend/tests/integration/NethermindService.int.js +++ b/launcher/src/backend/tests/integration/NethermindService.int.js @@ -11,16 +11,14 @@ jest.setTimeout(500000); test("nethermind installationm", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Nethermind--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Nethermind--integration-test--ubuntu-2204"); const serverSettings = { name: "Nethermind--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx21", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -38,7 +36,7 @@ test("nethermind installationm", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,7 +53,7 @@ test("nethermind installationm", async () => { await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); //install nethermind - let executionClient = serviceManager.getService("NethermindService", { network: "holesky", installDir: "/opt/stereum" }) + let executionClient = serviceManager.getService("NethermindService", { network: "holesky", installDir: "/opt/stereum" }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); executionClient.imageVersion = versions[executionClient.network][executionClient.service].slice(-1).pop(); @@ -84,7 +82,7 @@ test("nethermind installationm", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/30303\/tcp/); diff --git a/launcher/src/backend/tests/integration/NimbusBeaconService.int.js b/launcher/src/backend/tests/integration/NimbusBeaconService.int.js index 7fc0928032..514ea73a70 100755 --- a/launcher/src/backend/tests/integration/NimbusBeaconService.int.js +++ b/launcher/src/backend/tests/integration/NimbusBeaconService.int.js @@ -13,16 +13,14 @@ jest.setTimeout(1000000); test("nimbus validator import", async () => { //create server const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Nimbus--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Nimbus--integration-test--ubuntu-2204"); const serverSettings = { name: "Nimbus--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx31", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -40,7 +38,7 @@ test("nimbus validator import", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -57,18 +55,25 @@ test("nimbus validator import", async () => { await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); //install geth - let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }) + let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }); //install nimbus - let nimbusBC = serviceManager.getService("NimbusBeaconService", { network: "holesky", installDir: "/opt/stereum", executionClients: [geth] }) - - let nimbusVC = serviceManager.getService("NimbusValidatorService", { network: "holesky", installDir: "/opt/stereum", consensusClients: [nimbusBC] }) + let nimbusBC = serviceManager.getService("NimbusBeaconService", { + network: "holesky", + installDir: "/opt/stereum", + executionClients: [geth], + }); + + let nimbusVC = serviceManager.getService("NimbusValidatorService", { + network: "holesky", + installDir: "/opt/stereum", + consensusClients: [nimbusBC], + }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); geth.imageVersion = versions[geth.network][geth.service].slice(-1).pop(); - nimbusBC.imageVersion = versions[nimbusBC.network][nimbusBC.service].slice(-1).pop() - nimbusVC.imageVersion = versions[nimbusVC.network][nimbusVC.service].slice(-1).pop() - + nimbusBC.imageVersion = versions[nimbusBC.network][nimbusBC.service].slice(-1).pop(); + nimbusVC.imageVersion = versions[nimbusVC.network][nimbusVC.service].slice(-1).pop(); //write config and start geth await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()); @@ -92,7 +97,7 @@ test("nimbus validator import", async () => { '{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "fa52987837af01ec48e2b21f2078acef3368983943751013758052e07dae841d"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "8c055c8c504cd3ad20bcb1101431b2b1a506b1a4d0efdbd294d75c39c0f2268b"}}, "description": "", "pubkey": "948f092cb5b5cae121fdc14af0e4e5a90d03ab661266b700ded1c1ca4fd6f0a76f8dac187815409197bf036675571458", "path": "m/12381/3600/2/0/0", "uuid": "c7521eed-533a-4fd1-90b7-ad1aa0f24a2d", "version": 4}', ], passwords: ["MyTestPassword", "MyTestPassword", "MyTestPassword"], - }) + }); await validatorAccountManager.importKey(nimbusVC.id); //get logs @@ -123,7 +128,7 @@ test("nimbus validator import", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/9000\/tcp/); @@ -150,5 +155,4 @@ test("nimbus validator import", async () => { expect(VCstatus.stdout).toMatch(/Local validator attached/); expect(VCstatus.stdout).toMatch(/REST service started/); expect(VCstatus.stdout).toMatch(/Slot start/); - }); diff --git a/launcher/src/backend/tests/integration/NodeConnection.int.js b/launcher/src/backend/tests/integration/NodeConnection.int.js index c6a188bec5..2d044437ca 100755 --- a/launcher/src/backend/tests/integration/NodeConnection.int.js +++ b/launcher/src/backend/tests/integration/NodeConnection.int.js @@ -11,16 +11,14 @@ jest.setTimeout(500000); test("prepareStereumNode on ubuntu", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("NodeConnection--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("NodeConnection--integration-test--ubuntu-2204"); const serverSettings = { name: "NodeConnection--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx21", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -37,8 +35,7 @@ test("prepareStereumNode on ubuntu", async () => { const taskManager = new TaskManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) - + await nodeConnection.establish(taskManager); await nodeConnection.findOS(); @@ -58,7 +55,7 @@ test("prepareStereumNode on ubuntu", async () => { const ansibleRoles = await nodeConnection.sshService.exec("ls /opt/stereum/ansible/controls"); const ansibleVersion = await nodeConnection.sshService.exec("ansible --version"); - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); const ansible = ansibleVersion.stdout.split("\n")[0].split(" "); ansible[2] = ansible[2].split("."); diff --git a/launcher/src/backend/tests/integration/PrysmBeaconService.int.js b/launcher/src/backend/tests/integration/PrysmBeaconService.int.js index 99629f04c0..43bba1ebc4 100755 --- a/launcher/src/backend/tests/integration/PrysmBeaconService.int.js +++ b/launcher/src/backend/tests/integration/PrysmBeaconService.int.js @@ -12,16 +12,14 @@ jest.setTimeout(1000000); test("prysm validator import", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Prysm--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Prysm--integration-test--ubuntu-2204"); const serverSettings = { name: "Prysm--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx31", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -39,7 +37,7 @@ test("prysm validator import", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node // create stereum settings @@ -56,18 +54,25 @@ test("prysm validator import", async () => { await nodeConnection.findStereumSettings(); await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); - //install geth - let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }) + let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }); - let prysmBC = serviceManager.getService("PrysmBeaconService", { network: "holesky", installDir: "/opt/stereum", executionClients: [geth] }) + let prysmBC = serviceManager.getService("PrysmBeaconService", { + network: "holesky", + installDir: "/opt/stereum", + executionClients: [geth], + }); - let prysmVC = serviceManager.getService("PrysmValidatorService", { network: "holesky", installDir: "/opt/stereum", consensusClients: [prysmBC] }) + let prysmVC = serviceManager.getService("PrysmValidatorService", { + network: "holesky", + installDir: "/opt/stereum", + consensusClients: [prysmBC], + }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); geth.imageVersion = versions[geth.network][geth.service].slice(-1).pop(); - prysmBC.imageVersion = versions[prysmBC.network][prysmBC.service].slice(-1).pop() - prysmVC.imageVersion = versions[prysmVC.network][prysmVC.service].slice(-1).pop() + prysmBC.imageVersion = versions[prysmBC.network][prysmBC.service].slice(-1).pop(); + prysmVC.imageVersion = versions[prysmVC.network][prysmVC.service].slice(-1).pop(); //write config and start geth await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()); @@ -91,18 +96,12 @@ test("prysm validator import", async () => { '{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "fa52987837af01ec48e2b21f2078acef3368983943751013758052e07dae841d"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "8c055c8c504cd3ad20bcb1101431b2b1a506b1a4d0efdbd294d75c39c0f2268b"}}, "description": "", "pubkey": "948f092cb5b5cae121fdc14af0e4e5a90d03ab661266b700ded1c1ca4fd6f0a76f8dac187815409197bf036675571458", "path": "m/12381/3600/2/0/0", "uuid": "c7521eed-533a-4fd1-90b7-ad1aa0f24a2d", "version": 4}', ], passwords: ["MyTestPassword", "MyTestPassword", "MyTestPassword"], - }) + }); await validatorAccountManager.importKey(prysmVC.id); - await Promise.all([ - serviceManager.manageServiceState(prysmBC.id, "stopped"), - serviceManager.manageServiceState(prysmVC.id, "stopped"), - ]); + await Promise.all([serviceManager.manageServiceState(prysmBC.id, "stopped"), serviceManager.manageServiceState(prysmVC.id, "stopped")]); - await Promise.all([ - serviceManager.manageServiceState(prysmBC.id, "started"), - serviceManager.manageServiceState(prysmVC.id, "started"), - ]); + await Promise.all([serviceManager.manageServiceState(prysmBC.id, "started"), serviceManager.manageServiceState(prysmVC.id, "started")]); //get logs let condition = false; @@ -140,20 +139,18 @@ test("prysm validator import", async () => { log.debug(passwords_path); const ufw = await nodeConnection.sshService.exec("ufw status"); - const validatorAccounts = await nodeConnection.sshService.exec( - `cat ${wallet_path}/direct/accounts/all-accounts.keystore.json` - ); + const validatorAccounts = await nodeConnection.sshService.exec(`cat ${wallet_path}/direct/accounts/all-accounts.keystore.json`); const auth_token = await nodeConnection.sshService.exec(`cat ${wallet_path}/auth-token`); const docker = await nodeConnection.sshService.exec("docker ps"); let responseValidator = await nodeConnection.sshService.exec( "docker exec stereum-" + - prysmVC.id + - " /app/cmd/validator/validator accounts list --wallet-dir=/opt/app/data/wallets --wallet-password-file=/opt/app/data/passwords/wallet-password --accept-terms-of-use" + prysmVC.id + + " /app/cmd/validator/validator accounts list --wallet-dir=/opt/app/data/wallets --wallet-password-file=/opt/app/data/passwords/wallet-password --accept-terms-of-use" ); const runningValidator = responseValidator.stdout.replace("\x1B[93m3\x1B[0m", "3"); //remove yellow color coding // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/13001\/tcp/); diff --git a/launcher/src/backend/tests/integration/TekuBeaconService.int.js b/launcher/src/backend/tests/integration/TekuBeaconService.int.js index ad76e50bba..31d76c22a6 100755 --- a/launcher/src/backend/tests/integration/TekuBeaconService.int.js +++ b/launcher/src/backend/tests/integration/TekuBeaconService.int.js @@ -12,16 +12,14 @@ jest.setTimeout(1000000); test("teku validator import", async () => { const testServer = new HetznerServer(); - const keyResponse = await testServer.createSSHKey("Teku--integration-test--ubuntu-2204") + const keyResponse = await testServer.createSSHKey("Teku--integration-test--ubuntu-2204"); const serverSettings = { name: "Teku--integration-test--ubuntu-2204", image: "ubuntu-22.04", server_type: "cpx31", start_after_create: true, - ssh_keys: [ - keyResponse.ssh_key.id - ], + ssh_keys: [keyResponse.ssh_key.id], }; await testServer.create(serverSettings); @@ -39,7 +37,7 @@ test("teku validator import", async () => { const serviceManager = new ServiceManager(nodeConnection); await testServer.checkServerConnection(nodeConnection); - await nodeConnection.establish(taskManager) + await nodeConnection.establish(taskManager); //prepare node await nodeConnection.sshService.exec(` mkdir /etc/stereum && @@ -55,20 +53,23 @@ test("teku validator import", async () => { await nodeConnection.findStereumSettings(); await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path); - //install geth - let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }) + let geth = serviceManager.getService("GethService", { network: "holesky", installDir: "/opt/stereum" }); //install tekuBC - let tekuBC = serviceManager.getService("TekuBeaconService", { network: "holesky", installDir: "/opt/stereum", executionClients: [geth] }) + let tekuBC = serviceManager.getService("TekuBeaconService", { network: "holesky", installDir: "/opt/stereum", executionClients: [geth] }); //install tekuVC - let tekuVC = serviceManager.getService("TekuValidatorService", { network: "holesky", installDir: "/opt/stereum", consensusClients: [tekuBC] }) + let tekuVC = serviceManager.getService("TekuValidatorService", { + network: "holesky", + installDir: "/opt/stereum", + consensusClients: [tekuBC], + }); let versions = await nodeConnection.nodeUpdates.checkUpdates(); geth.imageVersion = versions[geth.network][geth.service].slice(-1).pop(); - tekuBC.imageVersion = versions[tekuBC.network][tekuBC.service].slice(-1).pop() - tekuVC.imageVersion = versions[tekuVC.network][tekuVC.service].slice(-1).pop() + tekuBC.imageVersion = versions[tekuBC.network][tekuBC.service].slice(-1).pop(); + tekuVC.imageVersion = versions[tekuVC.network][tekuVC.service].slice(-1).pop(); //write config and start geth await nodeConnection.writeServiceConfiguration(geth.buildConfiguration()); @@ -92,7 +93,7 @@ test("teku validator import", async () => { '{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "fa52987837af01ec48e2b21f2078acef3368983943751013758052e07dae841d"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "8c055c8c504cd3ad20bcb1101431b2b1a506b1a4d0efdbd294d75c39c0f2268b"}}, "description": "", "pubkey": "948f092cb5b5cae121fdc14af0e4e5a90d03ab661266b700ded1c1ca4fd6f0a76f8dac187815409197bf036675571458", "path": "m/12381/3600/2/0/0", "uuid": "c7521eed-533a-4fd1-90b7-ad1aa0f24a2d", "version": 4}', ], passwords: ["MyTestPassword", "MyTestPassword", "MyTestPassword"], - }) + }); await validatorAccountManager.importKey(tekuVC.id); //get logs @@ -130,12 +131,10 @@ test("teku validator import", async () => { const docker = await nodeConnection.sshService.exec("docker ps"); const teku_api_keystore = await nodeConnection.sshService.exec(`cat ${dataDir}/teku_api_keystore`); const teku_api_password = await nodeConnection.sshService.exec(`cat ${dataDir}/teku_api_password.txt`); - const validator_api_bearer = await nodeConnection.sshService.exec( - `cat ${dataDir}/validator/key-manager/validator-api-bearer` - ); + const validator_api_bearer = await nodeConnection.sshService.exec(`cat ${dataDir}/validator/key-manager/validator-api-bearer`); // destroy - await testServer.finishTestGracefully(nodeConnection) + await testServer.finishTestGracefully(nodeConnection); //check ufw expect(ufw.stdout).toMatch(/9001\/tcp/); @@ -161,8 +160,6 @@ test("teku validator import", async () => { expect(VCstatus.stdout).toMatch(/Successfully connected to beacon node event stream/); expect(VCstatus.stdout).toMatch(/Starting doppelganger detection for public keys: .{7}, .{7}, .{7}/); - - //check docker container expect(docker.stdout).toMatch(/consensys\/teku/); expect(docker.stdout).toMatch(/5051-5052->5051-5052/); diff --git a/launcher/src/backend/tests/unit/BesuService.test.js b/launcher/src/backend/tests/unit/BesuService.test.js index 0b44540c92..dec4cb66bb 100755 --- a/launcher/src/backend/tests/unit/BesuService.test.js +++ b/launcher/src/backend/tests/unit/BesuService.test.js @@ -22,37 +22,23 @@ test("buildByUserInput", () => { }); test("buildExecutionClientHttpEndpointUrl", () => { - const besuHttpEndpoint = BesuService.buildByUserInput( - "goerli", - [], - "/opt/stereum/besu" - ).buildExecutionClientHttpEndpointUrl(); + const besuHttpEndpoint = BesuService.buildByUserInput("goerli", [], "/opt/stereum/besu").buildExecutionClientHttpEndpointUrl(); expect(besuHttpEndpoint).toMatch(/http:\/\/stereum-.{36}:8545/); }); test("buildExecutionClientWsEndpointUrl", () => { - const besuWsEndpoint = BesuService.buildByUserInput( - "goerli", - [], - "/opt/stereum/besu" - ).buildExecutionClientWsEndpointUrl(); + const besuWsEndpoint = BesuService.buildByUserInput("goerli", [], "/opt/stereum/besu").buildExecutionClientWsEndpointUrl(); expect(besuWsEndpoint).toMatch(/ws:\/\/stereum-.{36}:8546/); }); test("buildExecutionClientMetricsEndpoint", () => { - const besuMetricsEndpoint = BesuService.buildByUserInput( - "goerli", - [], - "/opt/stereum/besu" - ).buildExecutionClientMetricsEndpoint(); + const besuMetricsEndpoint = BesuService.buildByUserInput("goerli", [], "/opt/stereum/besu").buildExecutionClientMetricsEndpoint(); expect(besuMetricsEndpoint).toMatch(/stereum-.{36}:9545/); }); test("buildPrometheusJob", () => { const besuPrometheusJob = BesuService.buildByUserInput("goerli", [], "/opt/stereum/besu").buildPrometheusJob(); - expect(besuPrometheusJob).toMatch( - /\n {2}- job_name: stereum-.{36}\n {4}static_configs:\n {6}- targets: \[stereum-.{36}:9545]/ - ); + expect(besuPrometheusJob).toMatch(/\n {2}- job_name: stereum-.{36}\n {4}static_configs:\n {6}- targets: \[stereum-.{36}:9545]/); }); test("buildByConfiguration", () => { diff --git a/launcher/src/backend/tests/unit/ErigonService.test.js b/launcher/src/backend/tests/unit/ErigonService.test.js index 59136aa4ee..0e83d235a3 100755 --- a/launcher/src/backend/tests/unit/ErigonService.test.js +++ b/launcher/src/backend/tests/unit/ErigonService.test.js @@ -6,15 +6,11 @@ test("id test", () => { }); test("network test goerli", () => { - expect(ErigonService.buildByUserInput("goerli", null, null).buildConfiguration().command).toContain( - "--chain=goerli" - ); + expect(ErigonService.buildByUserInput("goerli", null, null).buildConfiguration().command).toContain("--chain=goerli"); }); test("network test mainnet", () => { - expect(ErigonService.buildByUserInput("mainnet", null, null).buildConfiguration().command).not.toContain( - "--chain=goerli" - ); + expect(ErigonService.buildByUserInput("mainnet", null, null).buildConfiguration().command).not.toContain("--chain=goerli"); }); test("user", () => { @@ -22,9 +18,7 @@ test("user", () => { }); test("image", () => { - expect(ErigonService.buildByUserInput("mainnet", null, null).buildConfiguration().image).toMatch( - /thorax\/erigon/ - ); + expect(ErigonService.buildByUserInput("mainnet", null, null).buildConfiguration().image).toMatch(/thorax\/erigon/); }); test("endpoint url", () => { @@ -45,18 +39,10 @@ test("empty ports", () => { test("ports", () => { expect( - ErigonService.buildByUserInput( - "goerli", - [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], - null - ).buildConfiguration().ports + ErigonService.buildByUserInput("goerli", [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], null).buildConfiguration().ports ).toHaveLength(1); expect( - ErigonService.buildByUserInput( - "goerli", - [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], - null - ).buildConfiguration().ports + ErigonService.buildByUserInput("goerli", [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], null).buildConfiguration().ports ).toContain("0.0.0.0:100:200/tcp"); }); @@ -76,11 +62,7 @@ test("multiple ports", () => { }); test("workingDir", () => { - const erigonConfig = ErigonService.buildByUserInput( - "goerli", - null, - "/opt/stereum/erigon" - ).buildConfiguration(); + const erigonConfig = ErigonService.buildByUserInput("goerli", null, "/opt/stereum/erigon").buildConfiguration(); expect(erigonConfig.volumes).toHaveLength(2); expect(erigonConfig.volumes).toContain("/opt/stereum/erigon-" + erigonConfig.id + "/data:/opt/data/erigon"); diff --git a/launcher/src/backend/tests/unit/GethService.test.js b/launcher/src/backend/tests/unit/GethService.test.js index 613463f2e1..d57251a004 100755 --- a/launcher/src/backend/tests/unit/GethService.test.js +++ b/launcher/src/backend/tests/unit/GethService.test.js @@ -10,9 +10,7 @@ test("network test goerli", () => { }); test("network test mainnet", () => { - expect(GethService.buildByUserInput("mainnet", null, null).buildConfiguration().command).not.toContain( - "--goerli" - ); + expect(GethService.buildByUserInput("mainnet", null, null).buildConfiguration().command).not.toContain("--goerli"); }); test("user", () => { @@ -20,9 +18,7 @@ test("user", () => { }); test("image", () => { - expect(GethService.buildByUserInput("mainnet", null, null).buildConfiguration().image).toMatch( - /ethereum\/client-go/ - ); + expect(GethService.buildByUserInput("mainnet", null, null).buildConfiguration().image).toMatch(/ethereum\/client-go/); }); test("endpoint url", () => { @@ -43,18 +39,10 @@ test("empty ports", () => { test("ports", () => { expect( - GethService.buildByUserInput( - "goerli", - [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], - null - ).buildConfiguration().ports + GethService.buildByUserInput("goerli", [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], null).buildConfiguration().ports ).toHaveLength(1); expect( - GethService.buildByUserInput( - "goerli", - [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], - null - ).buildConfiguration().ports + GethService.buildByUserInput("goerli", [new ServicePort(null, 100, 200, servicePortProtocol.tcp)], null).buildConfiguration().ports ).toContain("0.0.0.0:100:200/tcp"); }); diff --git a/launcher/src/backend/tests/unit/GrafanaService.test.js b/launcher/src/backend/tests/unit/GrafanaService.test.js index cb9eca997a..c52d3f0234 100755 --- a/launcher/src/backend/tests/unit/GrafanaService.test.js +++ b/launcher/src/backend/tests/unit/GrafanaService.test.js @@ -4,17 +4,10 @@ import { ServicePort, servicePortProtocol } from "../../ethereum-services/Servic test("buildConfiguration", () => { const ports = [new ServicePort("127.0.0.1", 3000, 3000, servicePortProtocol.tcp)]; - const grafanaService = GrafanaService.buildByUserInput( - "prater", - ports, - "/opt/stereum/grafana", - "nimbus" - ).buildConfiguration(); + const grafanaService = GrafanaService.buildByUserInput("prater", ports, "/opt/stereum/grafana", "nimbus").buildConfiguration(); expect(grafanaService.volumes).toHaveLength(3); - expect(grafanaService.volumes).toContain( - "/opt/stereum/grafana-" + grafanaService.id + "/provisioning:/etc/grafana/provisioning" - ); + expect(grafanaService.volumes).toContain("/opt/stereum/grafana-" + grafanaService.id + "/provisioning:/etc/grafana/provisioning"); expect(grafanaService.volumes).toContain("/opt/stereum/grafana-" + grafanaService.id + "/data:/var/lib/grafana"); expect(grafanaService.volumes).toContain("/opt/stereum/grafana-" + grafanaService.id + ":/etc/grafana"); expect(grafanaService.ports).toHaveLength(1); @@ -25,12 +18,7 @@ test("buildConfiguration", () => { }); test("getAvailablePorts", () => { - const grafanaServicePorts = GrafanaService.buildByUserInput( - "prater", - [], - "/opt/stereum/grafana", - "nimbus" - ).getAvailablePorts(); + const grafanaServicePorts = GrafanaService.buildByUserInput("prater", [], "/opt/stereum/grafana", "nimbus").getAvailablePorts(); expect(grafanaServicePorts).toHaveLength(1); }); diff --git a/launcher/src/backend/tests/unit/LighthouseBeaconService.test.js b/launcher/src/backend/tests/unit/LighthouseBeaconService.test.js index e876ff9dba..f12c6cb9df 100755 --- a/launcher/src/backend/tests/unit/LighthouseBeaconService.test.js +++ b/launcher/src/backend/tests/unit/LighthouseBeaconService.test.js @@ -23,10 +23,7 @@ test("buildConfiguration", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -75,10 +72,7 @@ test("buildConsensusClientHttpEndpointUrl", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const ports = [ @@ -113,10 +107,7 @@ test("getAvailablePorts", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const lhServicePorts = LighthouseBeaconService.buildByUserInput( @@ -145,10 +136,7 @@ test("network", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const lhServicePorts = LighthouseBeaconService.buildByUserInput( diff --git a/launcher/src/backend/tests/unit/LighthouseValidatorService.test.js b/launcher/src/backend/tests/unit/LighthouseValidatorService.test.js index 19bc6e3cf7..ee3d5c6763 100755 --- a/launcher/src/backend/tests/unit/LighthouseValidatorService.test.js +++ b/launcher/src/backend/tests/unit/LighthouseValidatorService.test.js @@ -39,39 +39,21 @@ test("LighthouseValidatorService buildConfiguration", () => { test("LighthouseValidatorService getAvailablePorts", () => { const ports = [new ServicePort("1.2.3.4", 303, 404, servicePortProtocol.udp)]; - const lhService = LighthouseValidatorService.buildByUserInput( - "prater", - ports, - "/opt/stereum/lh", - [], - "foobar" - ).getAvailablePorts(); + const lhService = LighthouseValidatorService.buildByUserInput("prater", ports, "/opt/stereum/lh", [], "foobar").getAvailablePorts(); expect(lhService).toHaveLength(1); }); test("LighthouseValidatorService autoupdate", () => { const ports = [new ServicePort("1.2.3.4", 303, 404, servicePortProtocol.udp)]; - const lhService = LighthouseValidatorService.buildByUserInput( - "prater", - ports, - "/opt/stereum/lh", - [], - "foobar" - ).buildConfiguration(); + const lhService = LighthouseValidatorService.buildByUserInput("prater", ports, "/opt/stereum/lh", [], "foobar").buildConfiguration(); expect(lhService.autoupdate).toBe(true); }); test("LighthouseValidatorService network", () => { const ports = [new ServicePort("1.2.3.4", 303, 404, servicePortProtocol.udp)]; - const lhService = LighthouseValidatorService.buildByUserInput( - "mainnet", - ports, - "/opt/stereum/lh", - [], - "foobar" - ).buildConfiguration(); + const lhService = LighthouseValidatorService.buildByUserInput("mainnet", ports, "/opt/stereum/lh", [], "foobar").buildConfiguration(); expect(lhService.network).toBe("mainnet"); }); diff --git a/launcher/src/backend/tests/unit/LodestarBeaconService.test.js b/launcher/src/backend/tests/unit/LodestarBeaconService.test.js index 7f46324491..6b4b979c8a 100755 --- a/launcher/src/backend/tests/unit/LodestarBeaconService.test.js +++ b/launcher/src/backend/tests/unit/LodestarBeaconService.test.js @@ -23,10 +23,7 @@ test("buildConfiguration", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -63,10 +60,7 @@ test("buildConsensusClientHttpEndpointUrl", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const ports = [ @@ -101,10 +95,7 @@ test("getAvailablePorts", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const lServicePorts = LodestarBeaconService.buildByUserInput( @@ -133,10 +124,7 @@ test("network", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const lServicePorts = LodestarBeaconService.buildByUserInput( diff --git a/launcher/src/backend/tests/unit/LodestarValidatorService.test.js b/launcher/src/backend/tests/unit/LodestarValidatorService.test.js index 529b818716..6454202d24 100755 --- a/launcher/src/backend/tests/unit/LodestarValidatorService.test.js +++ b/launcher/src/backend/tests/unit/LodestarValidatorService.test.js @@ -38,39 +38,21 @@ test("LodestarValidatorService buildConfiguration", () => { test("LodestarValidatorService getAvailablePorts", () => { const ports = [new ServicePort("1.2.3.4", 303, 404, servicePortProtocol.udp)]; - const lService = LodestarValidatorService.buildByUserInput( - "prater", - ports, - "/opt/stereum/l", - [], - "foobar" - ).getAvailablePorts(); + const lService = LodestarValidatorService.buildByUserInput("prater", ports, "/opt/stereum/l", [], "foobar").getAvailablePorts(); expect(lService).toHaveLength(1); }); test("LodestarValidatorService autoupdate", () => { const ports = [new ServicePort("1.2.3.4", 303, 404, servicePortProtocol.udp)]; - const lService = LodestarValidatorService.buildByUserInput( - "prater", - ports, - "/opt/stereum/l", - [], - "foobar" - ).buildConfiguration(); + const lService = LodestarValidatorService.buildByUserInput("prater", ports, "/opt/stereum/l", [], "foobar").buildConfiguration(); expect(lService.autoupdate).toBe(true); }); test("LodestarValidatorService network", () => { const ports = [new ServicePort("1.2.3.4", 303, 404, servicePortProtocol.udp)]; - const lService = LodestarValidatorService.buildByUserInput( - "mainnet", - ports, - "/opt/stereum/l", - [], - "foobar" - ).buildConfiguration(); + const lService = LodestarValidatorService.buildByUserInput("mainnet", ports, "/opt/stereum/l", [], "foobar").buildConfiguration(); expect(lService.network).toBe("mainnet"); }); diff --git a/launcher/src/backend/tests/unit/NethermindService.test.js b/launcher/src/backend/tests/unit/NethermindService.test.js index 738159ae1c..f2872e8944 100755 --- a/launcher/src/backend/tests/unit/NethermindService.test.js +++ b/launcher/src/backend/tests/unit/NethermindService.test.js @@ -4,11 +4,7 @@ import { ServicePort, servicePortProtocol } from "../../ethereum-services/Servic test("buildByUserInput", () => { const ports = [new ServicePort(null, 4040, 4040, servicePortProtocol.tcp)]; - const nethermindService = NethermindService.buildByUserInput( - "goerli", - ports, - "/opt/stereum/nethermind" - ).buildConfiguration(); + const nethermindService = NethermindService.buildByUserInput("goerli", ports, "/opt/stereum/nethermind").buildConfiguration(); expect(nethermindService.service).toBe("NethermindService"); expect(nethermindService.id).toMatch(/.{8}-.{4}-.{4}-.{4}-.{12}/); @@ -19,9 +15,7 @@ test("buildByUserInput", () => { expect(nethermindService.entrypoint).toContain("./nethermind"); expect(nethermindService.ports).toHaveLength(1); expect(nethermindService.ports).toContain("0.0.0.0:4040:4040/tcp"); - expect(nethermindService.volumes).toContain( - "/opt/stereum/nethermind-" + nethermindService.id + "/data:/opt/app/data" - ); + expect(nethermindService.volumes).toContain("/opt/stereum/nethermind-" + nethermindService.id + "/data:/opt/app/data"); expect(nethermindService.user).toBe("root"); expect(nethermindService.network).toBe("goerli"); }); @@ -54,14 +48,8 @@ test("buildExecutionClientMetricsEndpoint", () => { }); test("buildPrometheusJob", () => { - const nethermindPrometheusJob = NethermindService.buildByUserInput( - "goerli", - [], - "/opt/stereum/nethermind" - ).buildPrometheusJob(); - expect(nethermindPrometheusJob).toMatch( - /\n {2}- job_name: stereum-.{36}\n {4}static_configs:\n {6}- targets: \[stereum-.{36}:6060]/ - ); + const nethermindPrometheusJob = NethermindService.buildByUserInput("goerli", [], "/opt/stereum/nethermind").buildPrometheusJob(); + expect(nethermindPrometheusJob).toMatch(/\n {2}- job_name: stereum-.{36}\n {4}static_configs:\n {6}- targets: \[stereum-.{36}:6060]/); }); test("buildByConfiguration", () => { diff --git a/launcher/src/backend/tests/unit/NimbusBeaconService.test.js b/launcher/src/backend/tests/unit/NimbusBeaconService.test.js index dd6b06e7d8..538a41359a 100755 --- a/launcher/src/backend/tests/unit/NimbusBeaconService.test.js +++ b/launcher/src/backend/tests/unit/NimbusBeaconService.test.js @@ -23,10 +23,7 @@ test("buildConfiguration", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -82,10 +79,7 @@ test("buildConsensusClientWsEndpointUrl", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -115,10 +109,7 @@ test("getAvailablePorts", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const nimbusServicePorts = NimbusBeaconService.buildByUserInput( @@ -147,10 +138,7 @@ test("network", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const nimbusService = NimbusBeaconService.buildByUserInput( diff --git a/launcher/src/backend/tests/unit/PrometheusNodeExporterService.test.js b/launcher/src/backend/tests/unit/PrometheusNodeExporterService.test.js index c82ab22c2a..7e7f334d22 100755 --- a/launcher/src/backend/tests/unit/PrometheusNodeExporterService.test.js +++ b/launcher/src/backend/tests/unit/PrometheusNodeExporterService.test.js @@ -7,8 +7,7 @@ test("buildConfiguration", () => { }); test("buildPrometheusNodeExporterClientHttpEndpointUrl", () => { - const pneService = - PrometheusNodeExporterService.buildByUserInput().buildPrometheusNodeExporterClientHttpEndpointUrl(); + const pneService = PrometheusNodeExporterService.buildByUserInput().buildPrometheusNodeExporterClientHttpEndpointUrl(); expect(pneService).toMatch(/http:\/\/stereum-.{36}:9100/); }); diff --git a/launcher/src/backend/tests/unit/PrometheusService.test.js b/launcher/src/backend/tests/unit/PrometheusService.test.js index 4fa1882b09..b0461df8d3 100755 --- a/launcher/src/backend/tests/unit/PrometheusService.test.js +++ b/launcher/src/backend/tests/unit/PrometheusService.test.js @@ -46,13 +46,7 @@ test("buildConfiguration", () => { }); test("getAvailablePorts", () => { - const prometheus = PrometheusService.buildByUserInput( - "prater", - [], - "/opt/stereum/prometheus", - [], - [] - ).getAvailablePorts(); + const prometheus = PrometheusService.buildByUserInput("prater", [], "/opt/stereum/prometheus", [], []).getAvailablePorts(); expect(prometheus).toHaveLength(1); }); diff --git a/launcher/src/backend/tests/unit/PrysmBeaconService.test.js b/launcher/src/backend/tests/unit/PrysmBeaconService.test.js index dfa4cbd4dc..0320b45e28 100755 --- a/launcher/src/backend/tests/unit/PrysmBeaconService.test.js +++ b/launcher/src/backend/tests/unit/PrysmBeaconService.test.js @@ -23,10 +23,7 @@ test("buildConfiguration", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -38,7 +35,7 @@ test("buildConfiguration", () => { [] ).buildConfiguration(); - expect(prysm.command).toContain('--execution-endpoint=http-endpoint-string,http-endpoint-string'); + expect(prysm.command).toContain("--execution-endpoint=http-endpoint-string,http-endpoint-string"); expect(prysm.volumes).toHaveLength(4); expect(prysm.volumes).toContain("/opt/stereum/prysm-" + prysm.id + "/beacon:/opt/app/beacon"); expect(prysm.volumes).toContain("/opt/stereum/prysm-" + prysm.id + "/genesis:/opt/app/genesis"); @@ -64,10 +61,7 @@ test("buildConsensusClientHttpEndpointUrl", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const ports = [ @@ -102,10 +96,7 @@ test("buildConsensusClientGateway", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const ports = [ @@ -140,10 +131,7 @@ test("buildConsensusClientEndpoint", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const ports = [ @@ -189,10 +177,7 @@ test("getAvailablePorts", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -222,10 +207,7 @@ test("network", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); diff --git a/launcher/src/backend/tests/unit/PrysmValidatorService.test.js b/launcher/src/backend/tests/unit/PrysmValidatorService.test.js index 7a92e4d082..4f30c88d4b 100755 --- a/launcher/src/backend/tests/unit/PrysmValidatorService.test.js +++ b/launcher/src/backend/tests/unit/PrysmValidatorService.test.js @@ -29,8 +29,8 @@ test("buildConfiguration", () => { new PrysmBeaconService.PrysmBeaconService(), ]).buildConfiguration(); - expect(prysm.command).toContain('--beacon-rpc-provider=buildConsensusClientEndpoint'); - expect(prysm.command).toContain('--beacon-rpc-gateway-provider=buildConsensusClientGateway'); + expect(prysm.command).toContain("--beacon-rpc-provider=buildConsensusClientEndpoint"); + expect(prysm.command).toContain("--beacon-rpc-gateway-provider=buildConsensusClientGateway"); expect(prysm.volumes).toHaveLength(4); expect(prysm.volumes).toContain("/opt/stereum/prysm-" + prysm.id + "/data/db:/opt/app/data/db"); expect(prysm.volumes).toContain("/opt/stereum/prysm-" + prysm.id + "/data/wallets:/opt/app/data/wallets"); diff --git a/launcher/src/backend/tests/unit/SSVNetworkService.test.js b/launcher/src/backend/tests/unit/SSVNetworkService.test.js index 7d10658319..5328ef3682 100755 --- a/launcher/src/backend/tests/unit/SSVNetworkService.test.js +++ b/launcher/src/backend/tests/unit/SSVNetworkService.test.js @@ -3,10 +3,7 @@ import { ServicePort, servicePortProtocol } from "../../ethereum-services/Servic const log = require("electron-log"); test("buildConfiguration", () => { - const ports = [ - new ServicePort(null, 100, 200, servicePortProtocol.tcp), - new ServicePort(null, 101, 202, servicePortProtocol.udp), - ]; + const ports = [new ServicePort(null, 100, 200, servicePortProtocol.tcp), new ServicePort(null, 101, 202, servicePortProtocol.udp)]; jest.mock("../../ethereum-services/GethService"); const GethService = require("../../ethereum-services/GethService"); @@ -92,11 +89,7 @@ test("getServiceConfiguration", () => { "/opt/stereum/ssv", [new GethService.GethService()], [new LighthouseBeaconService.LighthouseBeaconService()] - ).getServiceConfiguration( - "prater", - [new GethService.GethService()], - [new LighthouseBeaconService.LighthouseBeaconService()] - ); + ).getServiceConfiguration("prater", [new GethService.GethService()], [new LighthouseBeaconService.LighthouseBeaconService()]); expect(ssvService).toBeDefined(); expect(ssvService).toMatch(/prater/); @@ -105,37 +98,19 @@ test("getServiceConfiguration", () => { }); test("getAvailablePorts", () => { - const service = SSVNetworkService.buildByUserInput( - "prater", - null, - "/opt/stereum/ssv", - [], - [] - ).getAvailablePorts(); + const service = SSVNetworkService.buildByUserInput("prater", null, "/opt/stereum/ssv", [], []).getAvailablePorts(); expect(service).toHaveLength(3); }); test("service name", () => { - const service = SSVNetworkService.buildByUserInput( - "prater", - null, - "/opt/stereum/ssv", - [], - [] - ).buildConfiguration(); + const service = SSVNetworkService.buildByUserInput("prater", null, "/opt/stereum/ssv", [], []).buildConfiguration(); expect(service.service).toMatch(/SSVNetworkService/); }); test("autoupdate", () => { - const service = SSVNetworkService.buildByUserInput( - "prater", - null, - "/opt/stereum/ssv", - [], - [] - ).buildConfiguration(); + const service = SSVNetworkService.buildByUserInput("prater", null, "/opt/stereum/ssv", [], []).buildConfiguration(); expect(service.autoupdate).toBe(true); }); diff --git a/launcher/src/backend/tests/unit/ServiceManager.test.js b/launcher/src/backend/tests/unit/ServiceManager.test.js index 87a5742508..b83a008604 100755 --- a/launcher/src/backend/tests/unit/ServiceManager.test.js +++ b/launcher/src/backend/tests/unit/ServiceManager.test.js @@ -141,8 +141,8 @@ test("addDependencies LighthouseBeaconService", () => { const lhService = LighthouseBeaconService.buildByUserInput("prater", [], "/opt/stereum/lh", [], []); const result = sm.addDependencies(lhService, [geth1, geth2]); - expect(result.command.join(" ")).toMatch(/--execution-endpoint=http:\/\/stereum-.{36}:8551,http:\/\/stereum-.{36}:8551/) - expect(result.dependencies.executionClients).toHaveLength(2) + expect(result.command.join(" ")).toMatch(/--execution-endpoint=http:\/\/stereum-.{36}:8551,http:\/\/stereum-.{36}:8551/); + expect(result.dependencies.executionClients).toHaveLength(2); }); test("addDependencies FlashbotsMevBoost", () => { @@ -152,8 +152,8 @@ test("addDependencies FlashbotsMevBoost", () => { const mevboost = FlashbotsMevBoostService.buildByUserInput("goerli"); const result = sm.addDependencies(mevboost, [lhService1, lhService2]); - expect(result).toHaveLength(2) - expect(result[0].command.join(" ")).toMatch(/--builder=http:\/\/stereum-.{36}:18550/) + expect(result).toHaveLength(2); + expect(result[0].command.join(" ")).toMatch(/--builder=http:\/\/stereum-.{36}:18550/); }); test("addConnection String", () => { @@ -173,7 +173,7 @@ test("addConnection String", () => { test("addConnection array empty dependencies", () => { const geth1 = GethService.buildByUserInput("goerli", [], "/opt/stereum/geth"); const lhService = LighthouseBeaconService.buildByUserInput("prater", [], "/opt/stereum/prysm", [geth1], []); - const dependencies = [] + const dependencies = []; const endpointCommand = "--execution-endpoint="; const filter = (e) => e.buildExecutionClientEngineRPCHttpEndpointUrl(); @@ -201,14 +201,14 @@ test("addConnection array", () => { test("addConnection String empty dependencies", () => { const geth1 = GethService.buildByUserInput("goerli", [], "/opt/stereum/geth"); const prysm = PrysmBeaconService.buildByUserInput("prater", [], "/opt/stereum/prysm", [geth1], []); - const dependencies = [] + const dependencies = []; const endpointCommand = "--execution-endpoint="; const filter = (e) => e.buildExecutionClientEngineRPCHttpEndpointUrl(); const sm = new ServiceManager(); const result = sm.addCommandConnection(prysm, endpointCommand, dependencies, filter); - expect(result).not.toContain('--execution-endpoint='); + expect(result).not.toContain("--execution-endpoint="); }); test("removeConnection String", () => { @@ -251,12 +251,8 @@ test("removeConnection String multiple endpoints", () => { const sm = new ServiceManager(); const result = sm.removeCommandConnection(command, id); - expect(result).not.toMatch( - /--beacon-rpc-provider="stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:4000,stereum-foo:3000,stereum-bar:2000"/ - ); - expect(result).not.toMatch( - /--beacon-rpc-gateway-provider=stereum-foo:3000,stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:3500/ - ); + expect(result).not.toMatch(/--beacon-rpc-provider="stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:4000,stereum-foo:3000,stereum-bar:2000"/); + expect(result).not.toMatch(/--beacon-rpc-gateway-provider=stereum-foo:3000,stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:3500/); expect(result).toMatch(/--beacon-rpc-provider="stereum-foo:3000,stereum-bar:2000"/); expect(result).toMatch(/--beacon-rpc-gateway-provider=stereum-foo:3000/); }); @@ -313,9 +309,7 @@ test("removeConnection array multiple endpoints", () => { const sm = new ServiceManager(); const result = sm.removeCommandConnection(command, id); - expect(result).not.toContain( - '--ee-endpoint="http://stereum-9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d:8551,foo:3000,bar:2000"' - ); + expect(result).not.toContain('--ee-endpoint="http://stereum-9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d:8551,foo:3000,bar:2000"'); expect(result).toContain('--ee-endpoint="foo:3000,bar:2000"'); }); @@ -332,9 +326,7 @@ test("change network", () => { services.push(BesuService.buildByUserInput(oldNetwork, [], installDir + "/besu")); services.push(NethermindService.buildByUserInput(oldNetwork, [], installDir + "/nethermind")); services.push(FlashbotsMevBoostService.buildByUserInput(oldNetwork, relayURL)); - services.push( - LighthouseBeaconService.buildByUserInput(oldNetwork, [], installDir + "/lighthouse", [], [], checkpointURL) - ); + services.push(LighthouseBeaconService.buildByUserInput(oldNetwork, [], installDir + "/lighthouse", [], [], checkpointURL)); services.push(LighthouseValidatorService.buildByUserInput(oldNetwork, [], installDir + "/lighthouse", [])); services.push(PrysmBeaconService.buildByUserInput(oldNetwork, [], installDir + "/prysm", [], [], checkpointURL)); services.push(PrysmValidatorService.buildByUserInput(oldNetwork, [], installDir + "/prysm", [])); @@ -353,9 +345,9 @@ test("change network", () => { } expect(services.map((s) => s.network)).not.toContain("goerli"); expect(services.find((s) => s.service === "FlashbotsMevBoostService").entrypoint).toContain("-mainnet"); - expect(services.find((s) => s.service === "PrysmBeaconService").command).toContain('--mainnet'); + expect(services.find((s) => s.service === "PrysmBeaconService").command).toContain("--mainnet"); expect(services.find((s) => s.service === "PrysmBeaconService").command).not.toContain( - '--genesis-state=/opt/app/genesis/prysm-holesky-genesis.ssz' + "--genesis-state=/opt/app/genesis/prysm-holesky-genesis.ssz" ); expect(services.find((s) => s.service === "LighthouseBeaconService").command).toContain("--network=mainnet"); }); diff --git a/launcher/src/backend/tests/unit/ServicePort.test.js b/launcher/src/backend/tests/unit/ServicePort.test.js index 442d161a3e..a2cd0e5490 100755 --- a/launcher/src/backend/tests/unit/ServicePort.test.js +++ b/launcher/src/backend/tests/unit/ServicePort.test.js @@ -5,9 +5,7 @@ test("serviceport any destination ip", () => { }); test("serviceport specific destination ip", () => { - expect(new ServicePort("8.8.8.8", 1234, 5678, servicePortProtocol.udp).buildPortMapping()).toBe( - "8.8.8.8:1234:5678/udp" - ); + expect(new ServicePort("8.8.8.8", 1234, 5678, servicePortProtocol.udp).buildPortMapping()).toBe("8.8.8.8:1234:5678/udp"); }); test("buildByConfig", () => { diff --git a/launcher/src/backend/tests/unit/ServiceVolume.test.js b/launcher/src/backend/tests/unit/ServiceVolume.test.js index 03e7d17cce..c23d7b772b 100755 --- a/launcher/src/backend/tests/unit/ServiceVolume.test.js +++ b/launcher/src/backend/tests/unit/ServiceVolume.test.js @@ -1,9 +1,7 @@ import { ServiceVolume } from "../../ethereum-services/ServiceVolume"; test("servicevolume", () => { - expect(new ServiceVolume("/opt/stereum/foo", "/opt/app/data").buildVolumeMapping()).toBe( - "/opt/stereum/foo:/opt/app/data" - ); + expect(new ServiceVolume("/opt/stereum/foo", "/opt/app/data").buildVolumeMapping()).toBe("/opt/stereum/foo:/opt/app/data"); }); test("buildByConfig", () => { diff --git a/launcher/src/backend/tests/unit/StringUtils.test.js b/launcher/src/backend/tests/unit/StringUtils.test.js index e410bd0253..caca363c08 100755 --- a/launcher/src/backend/tests/unit/StringUtils.test.js +++ b/launcher/src/backend/tests/unit/StringUtils.test.js @@ -1,9 +1,7 @@ import { StringUtils } from "../../StringUtils"; test("escapeStringForShell small json", () => { - expect(StringUtils.escapeStringForShell(JSON.stringify({ foo: "bar", xyz: 123 }))).toEqual( - '"{\\"foo\\":\\"bar\\",\\"xyz\\":123}"' - ); + expect(StringUtils.escapeStringForShell(JSON.stringify({ foo: "bar", xyz: 123 }))).toEqual('"{\\"foo\\":\\"bar\\",\\"xyz\\":123}"'); }); test("escapeStringForShell simple String", () => { diff --git a/launcher/src/backend/tests/unit/TekuBeaconService.test.js b/launcher/src/backend/tests/unit/TekuBeaconService.test.js index 13efabc7e2..a307ace059 100755 --- a/launcher/src/backend/tests/unit/TekuBeaconService.test.js +++ b/launcher/src/backend/tests/unit/TekuBeaconService.test.js @@ -25,10 +25,7 @@ test("buildConfiguration", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -72,10 +69,7 @@ test("buildConsensusClientHttpEndpointUrl", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); @@ -117,10 +111,7 @@ test("getAvailablePorts", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const tekuServicePorts = TekuBeaconService.buildByUserInput( @@ -150,10 +141,7 @@ test("network", () => { service: "GethService", }; }), - volumes: [ - new ServiceVolume("some/path/data", "some/path/other/data"), - new ServiceVolume("some/path/engine.jwt", "/engine.jwt"), - ], + volumes: [new ServiceVolume("some/path/data", "some/path/other/data"), new ServiceVolume("some/path/engine.jwt", "/engine.jwt")], }; }); const tekuService = TekuBeaconService.buildByUserInput( diff --git a/launcher/src/background.js b/launcher/src/background.js index 8dcfcd53c8..6c3dd06ee4 100755 --- a/launcher/src/background.js +++ b/launcher/src/background.js @@ -506,12 +506,7 @@ ipcMain.handle("getCurrentEpochSlot", async (event, args) => { ipcMain.handle("beginAuthSetup", async (event, args) => { const current_window = event.sender; - return await authenticationService.beginAuthSetup( - args.timeBased, - args.increaseTimeLimit, - args.enableRateLimit, - current_window - ); + return await authenticationService.beginAuthSetup(args.timeBased, args.increaseTimeLimit, args.enableRateLimit, current_window); }); ipcMain.handle("finishAuthSetup", async () => { diff --git a/launcher/src/components/UI/base-header/components/menu/SingleMenu.vue b/launcher/src/components/UI/base-header/components/menu/SingleMenu.vue index 3ee2327d53..fa18dbf37c 100644 --- a/launcher/src/components/UI/base-header/components/menu/SingleMenu.vue +++ b/launcher/src/components/UI/base-header/components/menu/SingleMenu.vue @@ -34,10 +34,7 @@ const handleClick = () => { const menuIcon = computed(() => { if (props.item.name !== "Available Update") { return props.item.icon; - } else if ( - props.item.name === "Available Update" && - (headerStore.isUpdateAvailable || headerStore.isOsUpdateAvailable) - ) { + } else if (props.item.name === "Available Update" && (headerStore.isUpdateAvailable || headerStore.isOsUpdateAvailable)) { return props.item.activeIcon; } else { return props.item.icon; diff --git a/launcher/src/components/UI/base-header/components/modals/LogoutModal.vue b/launcher/src/components/UI/base-header/components/modals/LogoutModal.vue index d793ac1b2f..c698126d5f 100755 --- a/launcher/src/components/UI/base-header/components/modals/LogoutModal.vue +++ b/launcher/src/components/UI/base-header/components/modals/LogoutModal.vue @@ -1,9 +1,6 @@