diff --git a/.gitignore b/.gitignore index 0ac3294..94652ff 100644 --- a/.gitignore +++ b/.gitignore @@ -89,4 +89,6 @@ lerna-debug.log .DS_Store Thumbs.db -*.obsidian* \ No newline at end of file +*.obsidian* +_site/ +_site/* \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 62aec04..ba4d87a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,14 @@ // this file breaks if it's formatted "[sitemap]": { "editor.formatOnSave": false - } + }, + "spellright.language": [ + "en" + ], + "spellright.documentTypes": [ + "latex", + "plaintext", + "markdown" + ], + "djlint.showInstallError": false } \ No newline at end of file diff --git a/_site/approach/index.html b/_site/approach/index.html deleted file mode 100644 index f6328d2..0000000 --- a/_site/approach/index.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - Approach - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
- -

What to expect?

-

- Every problem is unique, so it's important to get a clear picture from the - start. That way, we can adapt our approach to fit your situation. -
- - Note: You can expand every step below the image to see more details. - -

- -approach process image - - -
- Step 1: Intro meeting -

- We'll begin with a intro meeting. This is an open conversation about your goals, the challenges you're facing and what you are looking for. We'll explore wether and how we can work together. - -

-
- -
- -
- Step 2: Shared understanding -

- If the next step isn't clear yet, we can dive deeper with a Discovery Hackathon* During this hands-on session we'll further explore your goals, challenges, systems & processes together. This also means sketching out solutions or testing assumptions to create a shared understanding. Whether or not we end up working together, you'll walk away with new insights. And I'll be able to make a realistic proposal. - -
- *Timeboxed between 2 - 4 hours - -

-
- -
- -
- Step 3: Proposal -

- I'll create a proposal outlining the scope, deliverables, timeline, and budget. We'll go through it together to make sure we're on the same page. - -

-
- -
- -
- Step 4: Agreement -

- Once we agree on the proposal, we'll finalise the formal things with a simple agreement. - -

-
- -
- -
- Step 5: Kickoff -

- We schedule the start date, set up communication channels, and get started. You'll know exactly what to expect and when. - -

-
- -
- -
- Step 6: Iteration & delivery -

- I'll deliver work in close collaboration with you. You'll get regular updates where I'll ask for feedback. - -

-
- -
- -
- Step 7: Wrapping up & Looking Ahead -

- Once I've delivered what we have agreed upon, we'll do a retrospective. From there, we can discuss what next step best fits your needs. We either wrap things up, start a new phase, or move into a support/maintenance phase. - -

-
- - -

Why work with me?

-

- With over 14 years in IT, I've held various roles from sysadmin and - application management to consultancy. Along the way, I achieved part-time - degrees in IT service management and IT & business. I enjoy the challenge of a - good problem, analysing symptoms, identifying what's wrong and finding a - solution. -

-

- Over time, I naturally moved toward data integration work (which I find most - enjoyable). I believe that the most transformative tech solutions begin with a - deep understanding of the problem. Thanks to my broad experience, I bring both - technical and business perspectives to every project. This allows me to - understand your challenges from multiple angles and deliver solutions that - stick. -

- -
-
-
-
- - - - diff --git a/_site/assets/images/IMG_3516.jpeg b/_site/assets/images/IMG_3516.jpeg deleted file mode 100644 index 12001c5..0000000 Binary files a/_site/assets/images/IMG_3516.jpeg and /dev/null differ diff --git a/_site/assets/images/IMG_3547.jpeg b/_site/assets/images/IMG_3547.jpeg deleted file mode 100644 index f6f70d5..0000000 Binary files a/_site/assets/images/IMG_3547.jpeg and /dev/null differ diff --git a/_site/assets/images/image.png b/_site/assets/images/image.png deleted file mode 100644 index cf57829..0000000 Binary files a/_site/assets/images/image.png and /dev/null differ diff --git a/_site/assets/images/logo.svg b/_site/assets/images/logo.svg deleted file mode 100644 index 568cb43..0000000 --- a/_site/assets/images/logo.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - - diff --git a/_site/assets/images/mra-beeline-bike.jpeg b/_site/assets/images/mra-beeline-bike.jpeg deleted file mode 100644 index 12001c5..0000000 Binary files a/_site/assets/images/mra-beeline-bike.jpeg and /dev/null differ diff --git a/_site/assets/images/mra-beeline-device.jpeg b/_site/assets/images/mra-beeline-device.jpeg deleted file mode 100644 index 44be880..0000000 Binary files a/_site/assets/images/mra-beeline-device.jpeg and /dev/null differ diff --git a/_site/assets/images/mra-beeline-mra-screenshot.png b/_site/assets/images/mra-beeline-mra-screenshot.png deleted file mode 100644 index cf57829..0000000 Binary files a/_site/assets/images/mra-beeline-mra-screenshot.png and /dev/null differ diff --git a/_site/assets/images/mra-beeline-screenshot.jpeg b/_site/assets/images/mra-beeline-screenshot.jpeg deleted file mode 100644 index f6f70d5..0000000 Binary files a/_site/assets/images/mra-beeline-screenshot.jpeg and /dev/null differ diff --git a/_site/assets/images/mra-screenshot.jpeg b/_site/assets/images/mra-screenshot.jpeg deleted file mode 100644 index f6f70d5..0000000 Binary files a/_site/assets/images/mra-screenshot.jpeg and /dev/null differ diff --git a/_site/assets/images/profilepic.png b/_site/assets/images/profilepic.png deleted file mode 100644 index 489def9..0000000 Binary files a/_site/assets/images/profilepic.png and /dev/null differ diff --git a/_site/assets/images/what-to expect.png b/_site/assets/images/what-to expect.png deleted file mode 100644 index 879f49b..0000000 Binary files a/_site/assets/images/what-to expect.png and /dev/null differ diff --git a/_site/assets/scripts/app.js b/_site/assets/scripts/app.js deleted file mode 100644 index 669037d..0000000 --- a/_site/assets/scripts/app.js +++ /dev/null @@ -1,109 +0,0 @@ -const fileInput = document.getElementById("file-input"); -fileInput.addEventListener("click", () => { - fileInput.value = ""; - clearMessage(); - hideDownloadButton(); -}); -const messageDisplay = document.getElementById("message"); - -fileInput.addEventListener("change", handleFileSelection); - -async function readXsl() { - const response = await fetch("./src/beeline.xsl"); - const xslText = await response.text(); - const parser = new DOMParser(); - return parser.parseFromString(xslText, "application/xml"); -} - -// Displays a message to the user -function showMessage(message, type) { - messageDisplay.textContent = message; - messageDisplay.style.color = type === "error" ? "red" : "green"; -} - -function createDownloadButton(resultString, fileName) { - const blob = new Blob([resultString], { type: "application/xml" }); - const url = URL.createObjectURL(blob); - - document.getElementById("download-container").innerHTML = ""; // Clear previous - - const downloadButton = document.createElement("button"); - downloadButton.textContent = "Download"; - downloadButton.id = "download-button"; - document.getElementById("download-container").appendChild(downloadButton); - - const downloadLink = document.createElement("a"); - downloadLink.href = url; - downloadLink.download = createNewFileName(fileName); - - document.getElementById("download-button").addEventListener("click", () => { - downloadLink.click(); - }); -} - -function hideDownloadButton() { - document.getElementById("download-container").innerHTML = ""; -} - -function createNewFileName(fileName) { - const namePart = fileName.replace(/\.gpx$/i, ""); - return `${namePart}_transformed.gpx`; -} -function clearMessage() { - messageDisplay.textContent = ""; -} - -function handleFileSelection(event) { - const file = event.target.files[0]; - const fileName = file.name; - - // Clear previous messages, buttons and files - hideDownloadButton(); - clearMessage(); - - // Validate file existence and type - if (!file) { - fileNameDisplay.textContent = ""; - hideDownloadButton(); - showMessage("No file selected. Please choose a file.", "error"); - return; - } - - if (!file.name.toLowerCase().endsWith(".gpx")) { - showMessage("Unsupported file type. Please select a .gpx file.", "error"); - return; - } - - // Read and transform the file - const reader = new FileReader(); - reader.onload = async () => { - const fileText = reader.result; - // fileContentDisplay.textContent = fileText; - - try { - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(fileText, "application/xml"); - const xsltDoc = await readXsl(); - - const xsltProcessor = new XSLTProcessor(); - xsltProcessor.importStylesheet(xsltDoc); - - // Perform the transformation, returning the result as a new XML document - const resultDoc = xsltProcessor.transformToDocument(xmlDoc); - - // Serialize the result document to a string - const serializer = new XMLSerializer(); - const resultString = serializer.serializeToString(resultDoc); - - createDownloadButton(resultString, fileName); - showMessage("File transformed successfully.", "success"); - } catch (err) { - console.error("Transformation error:", err); - showMessage("Error transforming the file.", "error"); - } - }; - reader.onerror = () => { - showMessage("Error reading the file. Please try again.", "error"); - }; - reader.readAsText(file); -} diff --git a/_site/assets/scripts/mra-beeline-converter.js b/_site/assets/scripts/mra-beeline-converter.js deleted file mode 100644 index 669037d..0000000 --- a/_site/assets/scripts/mra-beeline-converter.js +++ /dev/null @@ -1,109 +0,0 @@ -const fileInput = document.getElementById("file-input"); -fileInput.addEventListener("click", () => { - fileInput.value = ""; - clearMessage(); - hideDownloadButton(); -}); -const messageDisplay = document.getElementById("message"); - -fileInput.addEventListener("change", handleFileSelection); - -async function readXsl() { - const response = await fetch("./src/beeline.xsl"); - const xslText = await response.text(); - const parser = new DOMParser(); - return parser.parseFromString(xslText, "application/xml"); -} - -// Displays a message to the user -function showMessage(message, type) { - messageDisplay.textContent = message; - messageDisplay.style.color = type === "error" ? "red" : "green"; -} - -function createDownloadButton(resultString, fileName) { - const blob = new Blob([resultString], { type: "application/xml" }); - const url = URL.createObjectURL(blob); - - document.getElementById("download-container").innerHTML = ""; // Clear previous - - const downloadButton = document.createElement("button"); - downloadButton.textContent = "Download"; - downloadButton.id = "download-button"; - document.getElementById("download-container").appendChild(downloadButton); - - const downloadLink = document.createElement("a"); - downloadLink.href = url; - downloadLink.download = createNewFileName(fileName); - - document.getElementById("download-button").addEventListener("click", () => { - downloadLink.click(); - }); -} - -function hideDownloadButton() { - document.getElementById("download-container").innerHTML = ""; -} - -function createNewFileName(fileName) { - const namePart = fileName.replace(/\.gpx$/i, ""); - return `${namePart}_transformed.gpx`; -} -function clearMessage() { - messageDisplay.textContent = ""; -} - -function handleFileSelection(event) { - const file = event.target.files[0]; - const fileName = file.name; - - // Clear previous messages, buttons and files - hideDownloadButton(); - clearMessage(); - - // Validate file existence and type - if (!file) { - fileNameDisplay.textContent = ""; - hideDownloadButton(); - showMessage("No file selected. Please choose a file.", "error"); - return; - } - - if (!file.name.toLowerCase().endsWith(".gpx")) { - showMessage("Unsupported file type. Please select a .gpx file.", "error"); - return; - } - - // Read and transform the file - const reader = new FileReader(); - reader.onload = async () => { - const fileText = reader.result; - // fileContentDisplay.textContent = fileText; - - try { - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(fileText, "application/xml"); - const xsltDoc = await readXsl(); - - const xsltProcessor = new XSLTProcessor(); - xsltProcessor.importStylesheet(xsltDoc); - - // Perform the transformation, returning the result as a new XML document - const resultDoc = xsltProcessor.transformToDocument(xmlDoc); - - // Serialize the result document to a string - const serializer = new XMLSerializer(); - const resultString = serializer.serializeToString(resultDoc); - - createDownloadButton(resultString, fileName); - showMessage("File transformed successfully.", "success"); - } catch (err) { - console.error("Transformation error:", err); - showMessage("Error transforming the file.", "error"); - } - }; - reader.onerror = () => { - showMessage("Error reading the file. Please try again.", "error"); - }; - reader.readAsText(file); -} diff --git a/_site/assets/scripts/mra2beeline/app.js b/_site/assets/scripts/mra2beeline/app.js deleted file mode 100644 index b94d6c7..0000000 --- a/_site/assets/scripts/mra2beeline/app.js +++ /dev/null @@ -1,113 +0,0 @@ -const fileInput = document.getElementById("file-input"); -fileInput.addEventListener("click", () => { - fileInput.value = ""; - clearMessage(); - hideDownloadButton(); -}); -const messageDisplay = document.getElementById("message"); - -fileInput.addEventListener("change", handleFileSelection); - -async function readXsl() { - const response = await fetch("/assets/scripts/mra2beeline/beeline.xsl"); - const xslText = await response.text(); - const parser = new DOMParser(); - return parser.parseFromString(xslText, "application/xml"); -} - -// Displays a message to the user -function showMessage(message, type) { - messageDisplay.textContent = message; - messageDisplay.style.color = type === "error" ? "red" : "green"; -} - -function createDownloadButton(resultString, fileName) { - const blob = new Blob([resultString], { type: "application/xml" }); - const url = URL.createObjectURL(blob); - - document.getElementById("download-container").innerHTML = ""; // Clear previous - - const downloadButton = document.createElement("button"); - downloadButton.textContent = "Download"; - downloadButton.id = "download-button"; - document.getElementById("download-container").appendChild(downloadButton); - - const downloadLink = document.createElement("a"); - downloadLink.href = url; - downloadLink.download = createNewFileName(fileName); - - document.getElementById("download-button").addEventListener("click", () => { - downloadLink.click(); - hideDownloadButton(); - clearMessage(); - fileInput.value = ""; - showMessage("Done. Would you like to convert another gpx?", "success"); - }); -} - -function hideDownloadButton() { - document.getElementById("download-container").innerHTML = ""; -} - -function createNewFileName(fileName) { - const namePart = fileName.replace(/\.gpx$/i, ""); - return `${namePart} transformed.gpx`; -} -function clearMessage() { - messageDisplay.textContent = ""; -} - -function handleFileSelection(event) { - const file = event.target.files[0]; - const fileName = file.name; - - // Clear previous messages, buttons and files - hideDownloadButton(); - clearMessage(); - - // Validate file existence and type - if (!file) { - fileNameDisplay.textContent = ""; - hideDownloadButton(); - showMessage("No file selected. Please choose a file.", "error"); - return; - } - - if (!file.name.toLowerCase().endsWith(".gpx")) { - showMessage("Unsupported file type. Please select a .gpx file.", "error"); - return; - } - - // Read and transform the file - const reader = new FileReader(); - reader.onload = async () => { - const fileText = reader.result; - // fileContentDisplay.textContent = fileText; - - try { - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(fileText, "application/xml"); - const xsltDoc = await readXsl(); - - const xsltProcessor = new XSLTProcessor(); - xsltProcessor.importStylesheet(xsltDoc); - - // Perform the transformation, returning the result as a new XML document - const resultDoc = xsltProcessor.transformToDocument(xmlDoc); - - // Serialize the result document to a string - const serializer = new XMLSerializer(); - const resultString = serializer.serializeToString(resultDoc); - - createDownloadButton(resultString, fileName); - showMessage("File transformed successfully.", "success"); - } catch (err) { - console.error("Transformation error:", err); - showMessage("Error transforming the file.", "error"); - } - }; - reader.onerror = () => { - showMessage("Error reading the file. Please try again.", "error"); - }; - reader.readAsText(file); -} diff --git a/_site/assets/scripts/mra2beeline/beeline.xsl b/_site/assets/scripts/mra2beeline/beeline.xsl deleted file mode 100644 index ab92a78..0000000 --- a/_site/assets/scripts/mra2beeline/beeline.xsl +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - Beeline compatible waypoints below are converted from rtept nodes from the MyRouteApp gpx 1.1 - - - - - - - - Beeline compatible track points below are converted from the trkpt nodes from the MyRouteApp gpx 1.1 - - - - - - - - - - - \ No newline at end of file diff --git a/_site/assets/scripts/mra2beeline/mra-beeline-converter.js b/_site/assets/scripts/mra2beeline/mra-beeline-converter.js deleted file mode 100644 index 669037d..0000000 --- a/_site/assets/scripts/mra2beeline/mra-beeline-converter.js +++ /dev/null @@ -1,109 +0,0 @@ -const fileInput = document.getElementById("file-input"); -fileInput.addEventListener("click", () => { - fileInput.value = ""; - clearMessage(); - hideDownloadButton(); -}); -const messageDisplay = document.getElementById("message"); - -fileInput.addEventListener("change", handleFileSelection); - -async function readXsl() { - const response = await fetch("./src/beeline.xsl"); - const xslText = await response.text(); - const parser = new DOMParser(); - return parser.parseFromString(xslText, "application/xml"); -} - -// Displays a message to the user -function showMessage(message, type) { - messageDisplay.textContent = message; - messageDisplay.style.color = type === "error" ? "red" : "green"; -} - -function createDownloadButton(resultString, fileName) { - const blob = new Blob([resultString], { type: "application/xml" }); - const url = URL.createObjectURL(blob); - - document.getElementById("download-container").innerHTML = ""; // Clear previous - - const downloadButton = document.createElement("button"); - downloadButton.textContent = "Download"; - downloadButton.id = "download-button"; - document.getElementById("download-container").appendChild(downloadButton); - - const downloadLink = document.createElement("a"); - downloadLink.href = url; - downloadLink.download = createNewFileName(fileName); - - document.getElementById("download-button").addEventListener("click", () => { - downloadLink.click(); - }); -} - -function hideDownloadButton() { - document.getElementById("download-container").innerHTML = ""; -} - -function createNewFileName(fileName) { - const namePart = fileName.replace(/\.gpx$/i, ""); - return `${namePart}_transformed.gpx`; -} -function clearMessage() { - messageDisplay.textContent = ""; -} - -function handleFileSelection(event) { - const file = event.target.files[0]; - const fileName = file.name; - - // Clear previous messages, buttons and files - hideDownloadButton(); - clearMessage(); - - // Validate file existence and type - if (!file) { - fileNameDisplay.textContent = ""; - hideDownloadButton(); - showMessage("No file selected. Please choose a file.", "error"); - return; - } - - if (!file.name.toLowerCase().endsWith(".gpx")) { - showMessage("Unsupported file type. Please select a .gpx file.", "error"); - return; - } - - // Read and transform the file - const reader = new FileReader(); - reader.onload = async () => { - const fileText = reader.result; - // fileContentDisplay.textContent = fileText; - - try { - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(fileText, "application/xml"); - const xsltDoc = await readXsl(); - - const xsltProcessor = new XSLTProcessor(); - xsltProcessor.importStylesheet(xsltDoc); - - // Perform the transformation, returning the result as a new XML document - const resultDoc = xsltProcessor.transformToDocument(xmlDoc); - - // Serialize the result document to a string - const serializer = new XMLSerializer(); - const resultString = serializer.serializeToString(resultDoc); - - createDownloadButton(resultString, fileName); - showMessage("File transformed successfully.", "success"); - } catch (err) { - console.error("Transformation error:", err); - showMessage("Error transforming the file.", "error"); - } - }; - reader.onerror = () => { - showMessage("Error reading the file. Please try again.", "error"); - }; - reader.readAsText(file); -} diff --git a/_site/blog/index.html b/_site/blog/index.html deleted file mode 100644 index c780bd2..0000000 --- a/_site/blog/index.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - Blog - - - - - - - - - -
-
- - - -
-
- -
-
-
-
- - - - diff --git a/_site/bundle.css b/_site/bundle.css deleted file mode 100644 index 74f4532..0000000 --- a/_site/bundle.css +++ /dev/null @@ -1,155 +0,0 @@ -html { - scrollbar-gutter: stable; -} - -html, -body { - height: 100vh; - background-color: var(--pico-color-blue-50); -} - -body > footer { - position: sticky; - top: 100vh; -} - -nav { - display: flex; -} - -header { - background-color: var(--pico-color-blue-50); - /* background-color: #eef9ff; */ - border-bottom-style: inset; - border-bottom-width: 1px; - border-image: linear-gradient(to right, #eef9ff, #fff, #eef9ff); - border-image-slice: 1; -} - -#siteFooter { - background-color: #2e5077; - color: #eef9ff; - border-top-style: inset; - border-top-width: 1px; - border-image: linear-gradient(to right, #00a9ff, #89cff3, #00a9ff); - border-image-slice: 1; - padding: var(--pico-block-spacing-vertical); -} - -h1 { - padding-top: 0 !important; -} - -#logo { - max-height: 35px; -} - -.flex-header { - justify-content: space-between; - display: flex; - align-items: center; -} - -.flex-container { - flex-direction: column; - display: flex; -} - -#sidebar-picture { - padding-bottom: 10px; -} - -.grid-container { - display: grid; - grid-template-rows: auto 1fr; - grid-template-columns: 175px 1fr 1fr; - grid-template-areas: "sidebar main main"; -} - -@media only screen and (max-width: 768px) { - .grid-container { - grid-template-columns: 1fr; - grid-template-rows: auto auto; - grid-template-areas: - "main" - "sidebar"; - } - #sidebar-picture { - padding-bottom: none; - width: 145px; - } -} - -#sidebar { - grid-area: sidebar; - /* background-color: #89F; */ - padding: var(--pico-block-spacing-vertical); -} - -#main { - grid-area: main; - /* background-color: #E8F9; */ - padding: var(--pico-block-spacing-vertical); -} - -.roundedPhoto { - border-radius: 50%; - border-style: inset; - border-width: small; - border-color: var(--pico-primary-underline); -} - -#pagination { - text-align: center; -} - -.blogPostLinks { - color: unset; -} - -#emailLink { - unicode-bidi: bidi-override; - direction: rtl; -} - -#contactButton { - text-align: center; -} - -.centerImage { - display: block; - margin-left: auto; - margin-right: auto; -} - -.floatLeft { - float: left; - margin-right: var(--pico-block-spacing-vertical); -} - -.floatRight { - float: right; - margin-left: var(--pico-block-spacing-vertical); -} - -#message { - padding: var(--pico-block-spacing-vertical); - text-align: center; -} -#download-container { - text-align: center; -} - -pre.mermaid { - text-align: center; - background: transparent !important; - background-color: transparent !important; - border: none !important; - padding: 1rem; /* adjust as needed */ - font-family: inherit; /* removes monospace font if you don't want it */ -} - -@charset "UTF-8";/*! - * Pico CSS ✨ v2.1.1 (https://picocss.com) - * Copyright 2019-2025 - Licensed under MIT - */:host,:root{--pico-font-family-emoji:"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--pico-font-family-sans-serif:system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif,var(--pico-font-family-emoji);--pico-font-family-monospace:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace,var(--pico-font-family-emoji);--pico-font-family:var(--pico-font-family-sans-serif);--pico-line-height:1.5;--pico-font-weight:400;--pico-font-size:100%;--pico-text-underline-offset:0.1rem;--pico-border-radius:0.25rem;--pico-border-width:0.0625rem;--pico-outline-width:0.125rem;--pico-transition:0.2s ease-in-out;--pico-spacing:1rem;--pico-typography-spacing-vertical:1rem;--pico-block-spacing-vertical:var(--pico-spacing);--pico-block-spacing-horizontal:var(--pico-spacing);--pico-grid-column-gap:var(--pico-spacing);--pico-grid-row-gap:var(--pico-spacing);--pico-form-element-spacing-vertical:0.75rem;--pico-form-element-spacing-horizontal:1rem;--pico-group-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-primary-focus);--pico-group-box-shadow-focus-with-input:0 0 0 0.0625rem var(--pico-form-element-border-color);--pico-modal-overlay-backdrop-filter:blur(0.375rem);--pico-nav-element-spacing-vertical:1rem;--pico-nav-element-spacing-horizontal:0.5rem;--pico-nav-link-spacing-vertical:0.5rem;--pico-nav-link-spacing-horizontal:0.5rem;--pico-nav-breadcrumb-divider:">";--pico-icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pico-icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pico-icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--pico-icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--pico-icon-loading:url("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite; transform-origin: center center; %7D circle %7B stroke-dasharray: 75,100; stroke-dashoffset: -5; animation: dash 1.5s ease-in-out infinite; stroke-linecap: round; %7D @keyframes rotate %7B 0%25 %7B transform: rotate(0deg); %7D 100%25 %7B transform: rotate(360deg); %7D %7D @keyframes dash %7B 0%25 %7B stroke-dasharray: 1,100; stroke-dashoffset: 0; %7D 50%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -17.5; %7D 100%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -62; %7D %7D %3C/style%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='rgb(136, 145, 164)' stroke-width='4' /%3E%3C/g%3E%3C/svg%3E")}@media (min-width:576px){:host,:root{--pico-font-size:106.25%}}@media (min-width:768px){:host,:root{--pico-font-size:112.5%}}@media (min-width:1024px){:host,:root{--pico-font-size:118.75%}}@media (min-width:1280px){:host,:root{--pico-font-size:125%}}@media (min-width:1536px){:host,:root{--pico-font-size:131.25%}}a{--pico-text-decoration:underline}a.contrast,a.secondary{--pico-text-decoration:underline}small{--pico-font-size:0.875em}h1,h2,h3,h4,h5,h6{--pico-font-weight:700}h1{--pico-font-size:2rem;--pico-line-height:1.125;--pico-typography-spacing-top:3rem}h2{--pico-font-size:1.75rem;--pico-line-height:1.15;--pico-typography-spacing-top:2.625rem}h3{--pico-font-size:1.5rem;--pico-line-height:1.175;--pico-typography-spacing-top:2.25rem}h4{--pico-font-size:1.25rem;--pico-line-height:1.2;--pico-typography-spacing-top:1.874rem}h5{--pico-font-size:1.125rem;--pico-line-height:1.225;--pico-typography-spacing-top:1.6875rem}h6{--pico-font-size:1rem;--pico-line-height:1.25;--pico-typography-spacing-top:1.5rem}tfoot td,tfoot th,thead td,thead th{--pico-font-weight:600;--pico-border-width:0.1875rem}code,kbd,pre,samp{--pico-font-family:var(--pico-font-family-monospace)}kbd{--pico-font-weight:bolder}:where(select,textarea),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-outline-width:0.0625rem}[type=search]{--pico-border-radius:5rem}[type=checkbox],[type=radio]{--pico-border-width:0.125rem}[type=checkbox][role=switch]{--pico-border-width:0.1875rem}details.dropdown summary:not([role=button]){--pico-outline-width:0.0625rem}nav details.dropdown summary:focus-visible{--pico-outline-width:0.125rem}[role=search]{--pico-border-radius:5rem}[role=group]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus),[role=search]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus){--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}[role=group]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus),[role=search]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus){--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-contrast-focus)}[role=group] [role=button],[role=group] [type=button],[role=group] [type=submit],[role=group] button,[role=search] [role=button],[role=search] [type=button],[role=search] [type=submit],[role=search] button{--pico-form-element-spacing-horizontal:2rem}details summary[role=button]:not(.outline)::after{filter:brightness(0) invert(1)}[aria-busy=true]:not(input,select,textarea):is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0) invert(1)}:host(:not([data-theme=dark])),:root:not([data-theme=dark]),[data-theme=light]{color-scheme:light;--pico-background-color:#fff;--pico-color:#373c44;--pico-text-selection-color:rgba(116, 139, 248, 0.25);--pico-muted-color:#646b79;--pico-muted-border-color:rgb(231, 234, 239.5);--pico-primary:#2060df;--pico-primary-background:#2060df;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(32, 96, 223, 0.5);--pico-primary-hover:#184eb8;--pico-primary-hover-background:#1d59d0;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(116, 139, 248, 0.5);--pico-primary-inverse:#fff;--pico-secondary:#5d6b89;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(93, 107, 137, 0.5);--pico-secondary-hover:#48536b;--pico-secondary-hover-background:#48536b;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(93, 107, 137, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#181c25;--pico-contrast-background:#181c25;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(24, 28, 37, 0.5);--pico-contrast-hover:#000;--pico-contrast-hover-background:#000;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-secondary-hover);--pico-contrast-focus:rgba(93, 107, 137, 0.25);--pico-contrast-inverse:#fff;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(129, 145, 181, 0.01698),0.0335rem 0.067rem 0.402rem rgba(129, 145, 181, 0.024),0.0625rem 0.125rem 0.75rem rgba(129, 145, 181, 0.03),0.1125rem 0.225rem 1.35rem rgba(129, 145, 181, 0.036),0.2085rem 0.417rem 2.502rem rgba(129, 145, 181, 0.04302),0.5rem 1rem 6rem rgba(129, 145, 181, 0.06),0 0 0 0.0625rem rgba(129, 145, 181, 0.015);--pico-h1-color:#2d3138;--pico-h2-color:#373c44;--pico-h3-color:#424751;--pico-h4-color:#4d535e;--pico-h5-color:#5c6370;--pico-h6-color:#646b79;--pico-mark-background-color:rgb(252.5, 230.5, 191.5);--pico-mark-color:#0f1114;--pico-ins-color:rgb(28.5, 105.5, 84);--pico-del-color:rgb(136, 56.5, 53);--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:rgb(243, 244.5, 246.75);--pico-code-color:#646b79;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:rgb(251, 251.5, 252.25);--pico-form-element-selected-background-color:#dfe3eb;--pico-form-element-border-color:#cfd5e2;--pico-form-element-color:#23262c;--pico-form-element-placeholder-color:var(--pico-muted-color);--pico-form-element-active-background-color:#fff;--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:rgb(183.5, 105.5, 106.5);--pico-form-element-invalid-active-border-color:rgb(200.25, 79.25, 72.25);--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:rgb(76, 154.5, 137.5);--pico-form-element-valid-active-border-color:rgb(39, 152.75, 118.75);--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#bfc7d9;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#dfe3eb;--pico-range-active-border-color:#bfc7d9;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:var(--pico-background-color);--pico-card-border-color:var(--pico-muted-border-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:rgb(251, 251.5, 252.25);--pico-dropdown-background-color:#fff;--pico-dropdown-border-color:#eff1f4;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#eff1f4;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(232, 234, 237, 0.75);--pico-progress-background-color:#dfe3eb;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(76, 154.5, 137.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(200.25, 79.25, 72.25)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}:host(:not([data-theme=dark])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:root:not([data-theme=dark]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),[data-theme=light] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}@media only screen and (prefers-color-scheme:dark){:host(:not([data-theme])),:root:not([data-theme]){color-scheme:dark;--pico-background-color:rgb(19, 22.5, 30.5);--pico-color:#c2c7d0;--pico-text-selection-color:rgba(137, 153, 249, 0.1875);--pico-muted-color:#7b8495;--pico-muted-border-color:#202632;--pico-primary:#8999f9;--pico-primary-background:#2060df;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(137, 153, 249, 0.5);--pico-primary-hover:#aeb5fb;--pico-primary-hover-background:#3c71f7;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(137, 153, 249, 0.375);--pico-primary-inverse:#fff;--pico-secondary:#969eaf;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(150, 158, 175, 0.5);--pico-secondary-hover:#b3b9c5;--pico-secondary-hover-background:#5d6b89;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(144, 158, 190, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#dfe3eb;--pico-contrast-background:#eff1f4;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(223, 227, 235, 0.5);--pico-contrast-hover:#fff;--pico-contrast-hover-background:#fff;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-contrast-hover);--pico-contrast-focus:rgba(207, 213, 226, 0.25);--pico-contrast-inverse:#000;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(7, 8.5, 12, 0.01698),0.0335rem 0.067rem 0.402rem rgba(7, 8.5, 12, 0.024),0.0625rem 0.125rem 0.75rem rgba(7, 8.5, 12, 0.03),0.1125rem 0.225rem 1.35rem rgba(7, 8.5, 12, 0.036),0.2085rem 0.417rem 2.502rem rgba(7, 8.5, 12, 0.04302),0.5rem 1rem 6rem rgba(7, 8.5, 12, 0.06),0 0 0 0.0625rem rgba(7, 8.5, 12, 0.015);--pico-h1-color:#f0f1f3;--pico-h2-color:#e0e3e7;--pico-h3-color:#c2c7d0;--pico-h4-color:#b3b9c5;--pico-h5-color:#a4acba;--pico-h6-color:#8891a4;--pico-mark-background-color:#014063;--pico-mark-color:#fff;--pico-ins-color:#62af9a;--pico-del-color:rgb(205.5, 126, 123);--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:rgb(26, 30.5, 40.25);--pico-code-color:#8891a4;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:rgb(28, 33, 43.5);--pico-form-element-selected-background-color:#2a3140;--pico-form-element-border-color:#2a3140;--pico-form-element-color:#e0e3e7;--pico-form-element-placeholder-color:#8891a4;--pico-form-element-active-background-color:rgb(26, 30.5, 40.25);--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:rgb(149.5, 74, 80);--pico-form-element-invalid-active-border-color:rgb(183.25, 63.5, 59);--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#2a7b6f;--pico-form-element-valid-active-border-color:rgb(22, 137, 105.5);--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#333c4e;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#202632;--pico-range-active-border-color:#2a3140;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:#181c25;--pico-card-border-color:var(--pico-card-background-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:rgb(26, 30.5, 40.25);--pico-dropdown-background-color:#181c25;--pico-dropdown-border-color:#202632;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#202632;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(7.5, 8.5, 10, 0.75);--pico-progress-background-color:#202632;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}:host(:not([data-theme])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:root:not([data-theme]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}:host(:not([data-theme])) details summary[role=button].contrast:not(.outline)::after,:root:not([data-theme]) details summary[role=button].contrast:not(.outline)::after{filter:brightness(0)}:host(:not([data-theme])) [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before,:root:not([data-theme]) [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0)}}[data-theme=dark]{color-scheme:dark;--pico-background-color:rgb(19, 22.5, 30.5);--pico-color:#c2c7d0;--pico-text-selection-color:rgba(137, 153, 249, 0.1875);--pico-muted-color:#7b8495;--pico-muted-border-color:#202632;--pico-primary:#8999f9;--pico-primary-background:#2060df;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(137, 153, 249, 0.5);--pico-primary-hover:#aeb5fb;--pico-primary-hover-background:#3c71f7;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(137, 153, 249, 0.375);--pico-primary-inverse:#fff;--pico-secondary:#969eaf;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(150, 158, 175, 0.5);--pico-secondary-hover:#b3b9c5;--pico-secondary-hover-background:#5d6b89;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(144, 158, 190, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#dfe3eb;--pico-contrast-background:#eff1f4;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(223, 227, 235, 0.5);--pico-contrast-hover:#fff;--pico-contrast-hover-background:#fff;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-contrast-hover);--pico-contrast-focus:rgba(207, 213, 226, 0.25);--pico-contrast-inverse:#000;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(7, 8.5, 12, 0.01698),0.0335rem 0.067rem 0.402rem rgba(7, 8.5, 12, 0.024),0.0625rem 0.125rem 0.75rem rgba(7, 8.5, 12, 0.03),0.1125rem 0.225rem 1.35rem rgba(7, 8.5, 12, 0.036),0.2085rem 0.417rem 2.502rem rgba(7, 8.5, 12, 0.04302),0.5rem 1rem 6rem rgba(7, 8.5, 12, 0.06),0 0 0 0.0625rem rgba(7, 8.5, 12, 0.015);--pico-h1-color:#f0f1f3;--pico-h2-color:#e0e3e7;--pico-h3-color:#c2c7d0;--pico-h4-color:#b3b9c5;--pico-h5-color:#a4acba;--pico-h6-color:#8891a4;--pico-mark-background-color:#014063;--pico-mark-color:#fff;--pico-ins-color:#62af9a;--pico-del-color:rgb(205.5, 126, 123);--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:rgb(26, 30.5, 40.25);--pico-code-color:#8891a4;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:rgb(28, 33, 43.5);--pico-form-element-selected-background-color:#2a3140;--pico-form-element-border-color:#2a3140;--pico-form-element-color:#e0e3e7;--pico-form-element-placeholder-color:#8891a4;--pico-form-element-active-background-color:rgb(26, 30.5, 40.25);--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:rgb(149.5, 74, 80);--pico-form-element-invalid-active-border-color:rgb(183.25, 63.5, 59);--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#2a7b6f;--pico-form-element-valid-active-border-color:rgb(22, 137, 105.5);--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#333c4e;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#202632;--pico-range-active-border-color:#2a3140;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:#181c25;--pico-card-border-color:var(--pico-card-background-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:rgb(26, 30.5, 40.25);--pico-dropdown-background-color:#181c25;--pico-dropdown-border-color:#202632;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#202632;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(7.5, 8.5, 10, 0.75);--pico-progress-background-color:#202632;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}[data-theme=dark] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}[data-theme=dark] details summary[role=button].contrast:not(.outline)::after{filter:brightness(0)}[data-theme=dark] [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0)}[type=checkbox],[type=radio],[type=range],progress{accent-color:var(--pico-primary)}*,::after,::before{box-sizing:border-box;background-repeat:no-repeat}::after,::before{text-decoration:inherit;vertical-align:inherit}:where(:host),:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--pico-background-color);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:var(--pico-font-size);line-height:var(--pico-line-height);font-family:var(--pico-font-family);text-underline-offset:var(--pico-text-underline-offset);text-rendering:optimizeLegibility;overflow-wrap:break-word;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{width:100%;margin:0}main{display:block}body>footer,body>header,body>main{padding-block:var(--pico-block-spacing-vertical)}section{margin-bottom:var(--pico-block-spacing-vertical)}.container,.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:var(--pico-spacing);padding-left:var(--pico-spacing)}@media (min-width:576px){.container{max-width:510px;padding-right:0;padding-left:0}}@media (min-width:768px){.container{max-width:700px}}@media (min-width:1024px){.container{max-width:950px}}@media (min-width:1280px){.container{max-width:1200px}}@media (min-width:1536px){.container{max-width:1450px}}.grid{grid-column-gap:var(--pico-grid-column-gap);grid-row-gap:var(--pico-grid-row-gap);display:grid;grid-template-columns:1fr}@media (min-width:768px){.grid{grid-template-columns:repeat(auto-fit,minmax(0%,1fr))}}.grid>*{min-width:0}.overflow-auto{overflow:auto}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}address,blockquote,dl,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--pico-typography-spacing-vertical);color:var(--pico-color);font-style:normal;font-weight:var(--pico-font-weight)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--pico-typography-spacing-vertical);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:var(--pico-font-size);line-height:var(--pico-line-height);font-family:var(--pico-font-family)}h1{--pico-color:var(--pico-h1-color)}h2{--pico-color:var(--pico-h2-color)}h3{--pico-color:var(--pico-h3-color)}h4{--pico-color:var(--pico-h4-color)}h5{--pico-color:var(--pico-h5-color)}h6{--pico-color:var(--pico-h6-color)}:where(article,address,blockquote,dl,figure,form,ol,p,pre,table,ul)~:is(h1,h2,h3,h4,h5,h6){margin-top:var(--pico-typography-spacing-top)}p{margin-bottom:var(--pico-typography-spacing-vertical)}hgroup{margin-bottom:var(--pico-typography-spacing-vertical)}hgroup>*{margin-top:0;margin-bottom:0}hgroup>:not(:first-child):last-child{--pico-color:var(--pico-muted-color);--pico-font-weight:unset;font-size:1rem}:where(ol,ul) li{margin-bottom:calc(var(--pico-typography-spacing-vertical) * .25)}:where(dl,ol,ul) :where(dl,ol,ul){margin:0;margin-top:calc(var(--pico-typography-spacing-vertical) * .25)}ul li{list-style:square}mark{padding:.125rem .25rem;background-color:var(--pico-mark-background-color);color:var(--pico-mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--pico-typography-spacing-vertical) 0;padding:var(--pico-spacing);border-right:none;border-left:.25rem solid var(--pico-blockquote-border-color);border-inline-start:0.25rem solid var(--pico-blockquote-border-color);border-inline-end:none}blockquote footer{margin-top:calc(var(--pico-typography-spacing-vertical) * .5);color:var(--pico-blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--pico-ins-color);text-decoration:none}del{color:var(--pico-del-color)}::-moz-selection{background-color:var(--pico-text-selection-color)}::selection{background-color:var(--pico-text-selection-color)}:where(a:not([role=button])),[role=link]{--pico-color:var(--pico-primary);--pico-background-color:transparent;--pico-underline:var(--pico-primary-underline);outline:0;background-color:var(--pico-background-color);color:var(--pico-color);-webkit-text-decoration:var(--pico-text-decoration);text-decoration:var(--pico-text-decoration);text-decoration-color:var(--pico-underline);text-underline-offset:0.125em;transition:background-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition),-webkit-text-decoration var(--pico-transition);transition:background-color var(--pico-transition),color var(--pico-transition),text-decoration var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),color var(--pico-transition),text-decoration var(--pico-transition),box-shadow var(--pico-transition),-webkit-text-decoration var(--pico-transition)}:where(a:not([role=button])):is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-primary-hover);--pico-underline:var(--pico-primary-hover-underline);--pico-text-decoration:underline}:where(a:not([role=button])):focus-visible,[role=link]:focus-visible{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}:where(a:not([role=button])).secondary,[role=link].secondary{--pico-color:var(--pico-secondary);--pico-underline:var(--pico-secondary-underline)}:where(a:not([role=button])).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link].secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-secondary-hover);--pico-underline:var(--pico-secondary-hover-underline)}:where(a:not([role=button])).contrast,[role=link].contrast{--pico-color:var(--pico-contrast);--pico-underline:var(--pico-contrast-underline)}:where(a:not([role=button])).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link].contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-contrast-hover);--pico-underline:var(--pico-contrast-hover-underline)}a[role=button]{display:inline-block}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[role=button],[type=button],[type=file]::file-selector-button,[type=reset],[type=submit],button{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);--pico-color:var(--pico-primary-inverse);--pico-box-shadow:var(--pico-button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);border:var(--pico-border-width) solid var(--pico-border-color);border-radius:var(--pico-border-radius);outline:0;background-color:var(--pico-background-color);box-shadow:var(--pico-box-shadow);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:1rem;line-height:var(--pico-line-height);text-align:center;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}[role=button]:is(:hover,:active,:focus),[role=button]:is([aria-current]:not([aria-current=false])),[type=button]:is(:hover,:active,:focus),[type=button]:is([aria-current]:not([aria-current=false])),[type=file]::file-selector-button:is(:hover,:active,:focus),[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])),[type=reset]:is(:hover,:active,:focus),[type=reset]:is([aria-current]:not([aria-current=false])),[type=submit]:is(:hover,:active,:focus),[type=submit]:is([aria-current]:not([aria-current=false])),button:is(:hover,:active,:focus),button:is([aria-current]:not([aria-current=false])){--pico-background-color:var(--pico-primary-hover-background);--pico-border-color:var(--pico-primary-hover-border);--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--pico-color:var(--pico-primary-inverse)}[role=button]:focus,[role=button]:is([aria-current]:not([aria-current=false])):focus,[type=button]:focus,[type=button]:is([aria-current]:not([aria-current=false])):focus,[type=file]::file-selector-button:focus,[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])):focus,[type=reset]:focus,[type=reset]:is([aria-current]:not([aria-current=false])):focus,[type=submit]:focus,[type=submit]:is([aria-current]:not([aria-current=false])):focus,button:focus,button:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}[type=button],[type=reset],[type=submit]{margin-bottom:var(--pico-spacing)}:is(button,[type=submit],[type=button],[role=button]).secondary,[type=file]::file-selector-button,[type=reset]{--pico-background-color:var(--pico-secondary-background);--pico-border-color:var(--pico-secondary-border);--pico-color:var(--pico-secondary-inverse);cursor:pointer}:is(button,[type=submit],[type=button],[role=button]).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=file]::file-selector-button:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:var(--pico-secondary-hover-background);--pico-border-color:var(--pico-secondary-hover-border);--pico-color:var(--pico-secondary-inverse)}:is(button,[type=submit],[type=button],[role=button]).secondary:focus,:is(button,[type=submit],[type=button],[role=button]).secondary:is([aria-current]:not([aria-current=false])):focus,[type=file]::file-selector-button:focus,[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])):focus,[type=reset]:focus,[type=reset]:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}:is(button,[type=submit],[type=button],[role=button]).contrast{--pico-background-color:var(--pico-contrast-background);--pico-border-color:var(--pico-contrast-border);--pico-color:var(--pico-contrast-inverse)}:is(button,[type=submit],[type=button],[role=button]).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:var(--pico-contrast-hover-background);--pico-border-color:var(--pico-contrast-hover-border);--pico-color:var(--pico-contrast-inverse)}:is(button,[type=submit],[type=button],[role=button]).contrast:focus,:is(button,[type=submit],[type=button],[role=button]).contrast:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-contrast-focus)}:is(button,[type=submit],[type=button],[role=button]).outline,[type=reset].outline{--pico-background-color:transparent;--pico-color:var(--pico-primary);--pico-border-color:var(--pico-primary)}:is(button,[type=submit],[type=button],[role=button]).outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset].outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:transparent;--pico-color:var(--pico-primary-hover);--pico-border-color:var(--pico-primary-hover)}:is(button,[type=submit],[type=button],[role=button]).outline.secondary,[type=reset].outline{--pico-color:var(--pico-secondary);--pico-border-color:var(--pico-secondary)}:is(button,[type=submit],[type=button],[role=button]).outline.secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset].outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-secondary-hover);--pico-border-color:var(--pico-secondary-hover)}:is(button,[type=submit],[type=button],[role=button]).outline.contrast{--pico-color:var(--pico-contrast);--pico-border-color:var(--pico-contrast)}:is(button,[type=submit],[type=button],[role=button]).outline.contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-contrast-hover);--pico-border-color:var(--pico-contrast-hover)}:where(button,[type=submit],[type=reset],[type=button],[role=button])[disabled],:where(fieldset[disabled]) :is(button,[type=submit],[type=button],[type=reset],[role=button]){opacity:.5;pointer-events:none}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}td,th{padding:calc(var(--pico-spacing)/ 2) var(--pico-spacing);border-bottom:var(--pico-border-width) solid var(--pico-table-border-color);background-color:var(--pico-background-color);color:var(--pico-color);font-weight:var(--pico-font-weight);text-align:left;text-align:start}tfoot td,tfoot th{border-top:var(--pico-border-width) solid var(--pico-table-border-color);border-bottom:0}table.striped tbody tr:nth-child(odd) td,table.striped tbody tr:nth-child(odd) th{background-color:var(--pico-table-row-stripped-background-color)}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:host),svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-size:.875em;font-family:var(--pico-font-family)}pre code,pre samp{font-size:inherit;font-family:inherit}pre{-ms-overflow-style:scrollbar;overflow:auto}code,kbd,pre,samp{border-radius:var(--pico-border-radius);background:var(--pico-code-background-color);color:var(--pico-code-color);font-weight:var(--pico-font-weight);line-height:initial}code,kbd,samp{display:inline-block;padding:.375rem}pre{display:block;margin-bottom:var(--pico-spacing);overflow-x:auto}pre>code,pre>samp{display:block;padding:var(--pico-spacing);background:0 0;line-height:var(--pico-line-height)}kbd{background-color:var(--pico-code-kbd-background-color);color:var(--pico-code-kbd-color);vertical-align:baseline}figure{display:block;margin:0;padding:0}figure figcaption{padding:calc(var(--pico-spacing) * .5) 0;color:var(--pico-muted-color)}hr{height:0;margin:var(--pico-typography-spacing-vertical) 0;border:0;border-top:1px solid var(--pico-muted-border-color);color:inherit}[hidden],template{display:none!important}canvas{display:inline-block}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--pico-line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:0}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type=file],[type=range]{padding:0;border-width:0}input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2)}fieldset{width:100%;margin:0;margin-bottom:var(--pico-spacing);padding:0;border:0}fieldset legend,label{display:block;margin-bottom:calc(var(--pico-spacing) * .375);color:var(--pico-color);font-weight:var(--pico-form-label-font-weight,var(--pico-font-weight))}fieldset legend{margin-bottom:calc(var(--pico-spacing) * .5)}button[type=submit],input:not([type=checkbox],[type=radio]),select,textarea{width:100%}input:not([type=checkbox],[type=radio],[type=range],[type=file]),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal)}input,select,textarea{--pico-background-color:var(--pico-form-element-background-color);--pico-border-color:var(--pico-form-element-border-color);--pico-color:var(--pico-form-element-color);--pico-box-shadow:none;border:var(--pico-border-width) solid var(--pico-border-color);border-radius:var(--pico-border-radius);outline:0;background-color:var(--pico-background-color);box-shadow:var(--pico-box-shadow);color:var(--pico-color);font-weight:var(--pico-font-weight);transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}:where(select,textarea):not([readonly]):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus){--pico-background-color:var(--pico-form-element-active-background-color)}:where(select,textarea):not([readonly]):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus){--pico-border-color:var(--pico-form-element-active-border-color)}:where(select,textarea):not([readonly]):focus,input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus{--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color)}:where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea),input:not([type=submit],[type=button],[type=reset])[disabled],label[aria-disabled=true],select[disabled],textarea[disabled]{opacity:var(--pico-form-element-disabled-opacity);pointer-events:none}label[aria-disabled=true] input[disabled]{opacity:1}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid]{padding-right:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--pico-form-element-spacing-horizontal);padding-inline-start:var(--pico-form-element-spacing-horizontal)!important;padding-inline-end:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=false]:not(select){background-image:var(--pico-icon-valid)}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=true]:not(select){background-image:var(--pico-icon-invalid)}:where(input,select,textarea)[aria-invalid=false]{--pico-border-color:var(--pico-form-element-valid-border-color)}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--pico-border-color:var(--pico-form-element-valid-active-border-color)!important}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus):not([type=checkbox],[type=radio]){--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-valid-focus-color)!important}:where(input,select,textarea)[aria-invalid=true]{--pico-border-color:var(--pico-form-element-invalid-border-color)}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--pico-border-color:var(--pico-form-element-invalid-active-border-color)!important}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus):not([type=checkbox],[type=radio]){--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-invalid-focus-color)!important}[dir=rtl] :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}input::-webkit-input-placeholder,input::placeholder,select:invalid,textarea::-webkit-input-placeholder,textarea::placeholder{color:var(--pico-form-element-placeholder-color);opacity:1}input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:var(--pico-spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem);padding-left:var(--pico-form-element-spacing-horizontal);padding-inline-start:var(--pico-form-element-spacing-horizontal);padding-inline-end:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem);background-image:var(--pico-icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}select[multiple] option:checked{background:var(--pico-form-element-selected-background-color);color:var(--pico-form-element-color)}[dir=rtl] select:not([multiple],[size]){background-position:center left .75rem}textarea{display:block;resize:vertical}textarea[aria-invalid]{--pico-icon-height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);background-position:top right .75rem!important;background-size:1rem var(--pico-icon-height)!important}:where(input,select,textarea,fieldset,.grid)+small{display:block;width:100%;margin-top:calc(var(--pico-spacing) * -.75);margin-bottom:var(--pico-spacing);color:var(--pico-muted-color)}:where(input,select,textarea,fieldset,.grid)[aria-invalid=false]+small{color:var(--pico-ins-color)}:where(input,select,textarea,fieldset,.grid)[aria-invalid=true]+small{color:var(--pico-del-color)}label>:where(input,select,textarea){margin-top:calc(var(--pico-spacing) * .25)}label:has([type=checkbox],[type=radio]){width:-moz-fit-content;width:fit-content;cursor:pointer}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-inline-end:.5em;border-width:var(--pico-border-width);vertical-align:middle;cursor:pointer}[type=checkbox]::-ms-check,[type=radio]::-ms-check{display:none}[type=checkbox]:checked,[type=checkbox]:checked:active,[type=checkbox]:checked:focus,[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);background-image:var(--pico-icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=checkbox]~label,[type=radio]~label{display:inline-block;margin-bottom:0;cursor:pointer}[type=checkbox]~label:not(:last-of-type),[type=radio]~label:not(:last-of-type){margin-inline-end:1em}[type=checkbox]:indeterminate{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);background-image:var(--pico-icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=radio]{border-radius:50%}[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--pico-background-color:var(--pico-primary-inverse);border-width:.35em;background-image:none}[type=checkbox][role=switch]{--pico-background-color:var(--pico-switch-background-color);--pico-color:var(--pico-switch-color);width:2.25em;height:1.25em;border:var(--pico-border-width) solid var(--pico-border-color);border-radius:1.25em;background-color:var(--pico-background-color);line-height:1.25em}[type=checkbox][role=switch]:not([aria-invalid]){--pico-border-color:var(--pico-switch-background-color)}[type=checkbox][role=switch]:before{display:block;aspect-ratio:1;height:100%;border-radius:50%;background-color:var(--pico-color);box-shadow:var(--pico-switch-thumb-box-shadow);content:"";transition:margin .1s ease-in-out}[type=checkbox][role=switch]:focus{--pico-background-color:var(--pico-switch-background-color);--pico-border-color:var(--pico-switch-background-color)}[type=checkbox][role=switch]:checked{--pico-background-color:var(--pico-switch-checked-background-color);--pico-border-color:var(--pico-switch-checked-background-color);background-image:none}[type=checkbox][role=switch]:checked::before{margin-inline-start:calc(2.25em - 1.25em)}[type=checkbox][role=switch][disabled]{--pico-background-color:var(--pico-border-color)}[type=checkbox][aria-invalid=false]:checked,[type=checkbox][aria-invalid=false]:checked:active,[type=checkbox][aria-invalid=false]:checked:focus,[type=checkbox][role=switch][aria-invalid=false]:checked,[type=checkbox][role=switch][aria-invalid=false]:checked:active,[type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pico-background-color:var(--pico-form-element-valid-border-color)}[type=checkbox]:checked:active[aria-invalid=true],[type=checkbox]:checked:focus[aria-invalid=true],[type=checkbox]:checked[aria-invalid=true],[type=checkbox][role=switch]:checked:active[aria-invalid=true],[type=checkbox][role=switch]:checked:focus[aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true]{--pico-background-color:var(--pico-form-element-invalid-border-color)}[type=checkbox][aria-invalid=false]:checked,[type=checkbox][aria-invalid=false]:checked:active,[type=checkbox][aria-invalid=false]:checked:focus,[type=checkbox][role=switch][aria-invalid=false]:checked,[type=checkbox][role=switch][aria-invalid=false]:checked:active,[type=checkbox][role=switch][aria-invalid=false]:checked:focus,[type=radio][aria-invalid=false]:checked,[type=radio][aria-invalid=false]:checked:active,[type=radio][aria-invalid=false]:checked:focus{--pico-border-color:var(--pico-form-element-valid-border-color)}[type=checkbox]:checked:active[aria-invalid=true],[type=checkbox]:checked:focus[aria-invalid=true],[type=checkbox]:checked[aria-invalid=true],[type=checkbox][role=switch]:checked:active[aria-invalid=true],[type=checkbox][role=switch]:checked:focus[aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true],[type=radio]:checked:active[aria-invalid=true],[type=radio]:checked:focus[aria-invalid=true],[type=radio]:checked[aria-invalid=true]{--pico-border-color:var(--pico-form-element-invalid-border-color)}[type=color]::-webkit-color-swatch-wrapper{padding:0}[type=color]::-moz-focus-inner{padding:0}[type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--pico-border-radius) * .5)}[type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--pico-border-radius) * .5)}input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--pico-icon-position:0.75rem;--pico-icon-width:1rem;padding-right:calc(var(--pico-icon-width) + var(--pico-icon-position));background-image:var(--pico-icon-date);background-position:center right var(--pico-icon-position);background-size:var(--pico-icon-width) auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--pico-icon-time)}[type=date]::-webkit-calendar-picker-indicator,[type=datetime-local]::-webkit-calendar-picker-indicator,[type=month]::-webkit-calendar-picker-indicator,[type=time]::-webkit-calendar-picker-indicator,[type=week]::-webkit-calendar-picker-indicator{width:var(--pico-icon-width);margin-right:calc(var(--pico-icon-width) * -1);margin-left:var(--pico-icon-position);opacity:0}@-moz-document url-prefix(){[type=date],[type=datetime-local],[type=month],[type=time],[type=week]{padding-right:var(--pico-form-element-spacing-horizontal)!important;background-image:none!important}}[dir=rtl] :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}[type=file]{--pico-color:var(--pico-muted-color);margin-left:calc(var(--pico-outline-width) * -1);padding:calc(var(--pico-form-element-spacing-vertical) * .5) 0;padding-left:var(--pico-outline-width);border:0;border-radius:0;background:0 0}[type=file]::file-selector-button{margin-right:calc(var(--pico-spacing)/ 2);padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal)}[type=file]:is(:hover,:active,:focus)::file-selector-button{--pico-background-color:var(--pico-secondary-hover-background);--pico-border-color:var(--pico-secondary-hover-border)}[type=file]:focus::file-selector-button{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:0 0}[type=range]::-webkit-slider-runnable-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-webkit-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-moz-range-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-moz-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-ms-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-ms-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-webkit-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-moz-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-ms-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]:active,[type=range]:focus-within{--pico-range-border-color:var(--pico-range-active-border-color);--pico-range-thumb-color:var(--pico-range-thumb-active-color)}[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}[type=range]:active::-moz-range-thumb{transform:scale(1.25)}[type=range]:active::-ms-thumb{transform:scale(1.25)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{padding-inline-start:calc(var(--pico-form-element-spacing-horizontal) + 1.75rem);background-image:var(--pico-icon-search);background-position:center left calc(var(--pico-form-element-spacing-horizontal) + .125rem);background-size:1rem auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{padding-inline-start:calc(var(--pico-form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--pico-icon-search),var(--pico-icon-valid)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--pico-icon-search),var(--pico-icon-invalid)}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}details{display:block;margin-bottom:var(--pico-spacing)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--pico-transition)}details summary:not([role]){color:var(--pico-accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;margin-inline-start:calc(var(--pico-spacing,1rem) * .5);float:right;transform:rotate(-90deg);background-image:var(--pico-icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--pico-transition)}details summary:focus{outline:0}details summary:focus:not([role]){color:var(--pico-accordion-active-summary-color)}details summary:focus-visible:not([role]){outline:var(--pico-outline-width) solid var(--pico-primary-focus);outline-offset:calc(var(--pico-spacing,1rem) * 0.5);color:var(--pico-primary)}details summary[role=button]{width:100%;text-align:left}details summary[role=button]::after{height:calc(1rem * var(--pico-line-height,1.5))}details[open]>summary{margin-bottom:var(--pico-spacing)}details[open]>summary:not([role]):not(:focus){color:var(--pico-accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir=rtl] details summary{text-align:right}[dir=rtl] details summary::after{float:left;background-position:left center}article{margin-bottom:var(--pico-block-spacing-vertical);padding:var(--pico-block-spacing-vertical) var(--pico-block-spacing-horizontal);border-radius:var(--pico-border-radius);background:var(--pico-card-background-color);box-shadow:var(--pico-card-box-shadow)}article>footer,article>header{margin-right:calc(var(--pico-block-spacing-horizontal) * -1);margin-left:calc(var(--pico-block-spacing-horizontal) * -1);padding:calc(var(--pico-block-spacing-vertical) * .66) var(--pico-block-spacing-horizontal);background-color:var(--pico-card-sectioning-background-color)}article>header{margin-top:calc(var(--pico-block-spacing-vertical) * -1);margin-bottom:var(--pico-block-spacing-vertical);border-bottom:var(--pico-border-width) solid var(--pico-card-border-color);border-top-right-radius:var(--pico-border-radius);border-top-left-radius:var(--pico-border-radius)}article>footer{margin-top:var(--pico-block-spacing-vertical);margin-bottom:calc(var(--pico-block-spacing-vertical) * -1);border-top:var(--pico-border-width) solid var(--pico-card-border-color);border-bottom-right-radius:var(--pico-border-radius);border-bottom-left-radius:var(--pico-border-radius)}details.dropdown{position:relative;border-bottom:none}details.dropdown>a::after,details.dropdown>button::after,details.dropdown>summary::after{display:block;width:1rem;height:calc(1rem * var(--pico-line-height,1.5));margin-inline-start:.25rem;float:right;transform:rotate(0) translateX(.2rem);background-image:var(--pico-icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}nav details.dropdown{margin-bottom:0}details.dropdown>summary:not([role]){height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);border:var(--pico-border-width) solid var(--pico-form-element-border-color);border-radius:var(--pico-border-radius);background-color:var(--pico-form-element-background-color);color:var(--pico-form-element-placeholder-color);line-height:inherit;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}details.dropdown>summary:not([role]):active,details.dropdown>summary:not([role]):focus{border-color:var(--pico-form-element-active-border-color);background-color:var(--pico-form-element-active-background-color)}details.dropdown>summary:not([role]):focus{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color)}details.dropdown>summary:not([role]):focus-visible{outline:0}details.dropdown>summary:not([role])[aria-invalid=false]{--pico-form-element-border-color:var(--pico-form-element-valid-border-color);--pico-form-element-active-border-color:var(--pico-form-element-valid-focus-color);--pico-form-element-focus-color:var(--pico-form-element-valid-focus-color)}details.dropdown>summary:not([role])[aria-invalid=true]{--pico-form-element-border-color:var(--pico-form-element-invalid-border-color);--pico-form-element-active-border-color:var(--pico-form-element-invalid-focus-color);--pico-form-element-focus-color:var(--pico-form-element-invalid-focus-color)}nav details.dropdown{display:inline;margin:calc(var(--pico-nav-element-spacing-vertical) * -1) 0}nav details.dropdown>summary::after{transform:rotate(0) translateX(0)}nav details.dropdown>summary:not([role]){height:calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 2);padding:calc(var(--pico-nav-link-spacing-vertical) - var(--pico-border-width) * 2) var(--pico-nav-link-spacing-horizontal)}nav details.dropdown>summary:not([role]):focus-visible{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}details.dropdown>summary+ul{display:flex;z-index:99;position:absolute;left:0;flex-direction:column;width:100%;min-width:-moz-fit-content;min-width:fit-content;margin:0;margin-top:var(--pico-outline-width);padding:0;border:var(--pico-border-width) solid var(--pico-dropdown-border-color);border-radius:var(--pico-border-radius);background-color:var(--pico-dropdown-background-color);box-shadow:var(--pico-dropdown-box-shadow);color:var(--pico-dropdown-color);white-space:nowrap;opacity:0;transition:opacity var(--pico-transition),transform 0s ease-in-out 1s}details.dropdown>summary+ul[dir=rtl]{right:0;left:auto}details.dropdown>summary+ul li{width:100%;margin-bottom:0;padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal);list-style:none}details.dropdown>summary+ul li:first-of-type{margin-top:calc(var(--pico-form-element-spacing-vertical) * .5)}details.dropdown>summary+ul li:last-of-type{margin-bottom:calc(var(--pico-form-element-spacing-vertical) * .5)}details.dropdown>summary+ul li a{display:block;margin:calc(var(--pico-form-element-spacing-vertical) * -.5) calc(var(--pico-form-element-spacing-horizontal) * -1);padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal);overflow:hidden;border-radius:0;color:var(--pico-dropdown-color);text-decoration:none;text-overflow:ellipsis}details.dropdown>summary+ul li a:active,details.dropdown>summary+ul li a:focus,details.dropdown>summary+ul li a:focus-visible,details.dropdown>summary+ul li a:hover,details.dropdown>summary+ul li a[aria-current]:not([aria-current=false]){background-color:var(--pico-dropdown-hover-background-color)}details.dropdown>summary+ul li label{width:100%}details.dropdown>summary+ul li:has(label):hover{background-color:var(--pico-dropdown-hover-background-color)}details.dropdown[open]>summary{margin-bottom:0}details.dropdown[open]>summary+ul{transform:scaleY(1);opacity:1;transition:opacity var(--pico-transition),transform 0s ease-in-out 0s}details.dropdown[open]>summary::before{display:block;z-index:1;position:fixed;width:100vw;height:100vh;inset:0;background:0 0;content:"";cursor:default}label>details.dropdown{margin-top:calc(var(--pico-spacing) * .25)}[role=group],[role=search]{display:inline-flex;position:relative;width:100%;margin-bottom:var(--pico-spacing);border-radius:var(--pico-border-radius);box-shadow:var(--pico-group-box-shadow,0 0 0 transparent);vertical-align:middle;transition:box-shadow var(--pico-transition)}[role=group] input:not([type=checkbox],[type=radio]),[role=group] select,[role=group]>*,[role=search] input:not([type=checkbox],[type=radio]),[role=search] select,[role=search]>*{position:relative;flex:1 1 auto;margin-bottom:0}[role=group] input:not([type=checkbox],[type=radio]):not(:first-child),[role=group] select:not(:first-child),[role=group]>:not(:first-child),[role=search] input:not([type=checkbox],[type=radio]):not(:first-child),[role=search] select:not(:first-child),[role=search]>:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}[role=group] input:not([type=checkbox],[type=radio]):not(:last-child),[role=group] select:not(:last-child),[role=group]>:not(:last-child),[role=search] input:not([type=checkbox],[type=radio]):not(:last-child),[role=search] select:not(:last-child),[role=search]>:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}[role=group] input:not([type=checkbox],[type=radio]):focus,[role=group] select:focus,[role=group]>:focus,[role=search] input:not([type=checkbox],[type=radio]):focus,[role=search] select:focus,[role=search]>:focus{z-index:2}[role=group] [role=button]:not(:first-child),[role=group] [type=button]:not(:first-child),[role=group] [type=reset]:not(:first-child),[role=group] [type=submit]:not(:first-child),[role=group] button:not(:first-child),[role=group] input:not([type=checkbox],[type=radio]):not(:first-child),[role=group] select:not(:first-child),[role=search] [role=button]:not(:first-child),[role=search] [type=button]:not(:first-child),[role=search] [type=reset]:not(:first-child),[role=search] [type=submit]:not(:first-child),[role=search] button:not(:first-child),[role=search] input:not([type=checkbox],[type=radio]):not(:first-child),[role=search] select:not(:first-child){margin-left:calc(var(--pico-border-width) * -1)}[role=group] [role=button],[role=group] [type=button],[role=group] [type=reset],[role=group] [type=submit],[role=group] button,[role=search] [role=button],[role=search] [type=button],[role=search] [type=reset],[role=search] [type=submit],[role=search] button{width:auto}@supports selector(:has(*)){[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus),[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus){--pico-group-box-shadow:var(--pico-group-box-shadow-focus-with-button)}[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select,[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select{border-color:transparent}[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus),[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus){--pico-group-box-shadow:var(--pico-group-box-shadow-focus-with-input)}[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) button,[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) button{--pico-button-box-shadow:0 0 0 var(--pico-border-width) var(--pico-primary-border);--pico-button-hover-box-shadow:0 0 0 var(--pico-border-width) var(--pico-primary-hover-border)}[role=group] [role=button]:focus,[role=group] [type=button]:focus,[role=group] [type=reset]:focus,[role=group] [type=submit]:focus,[role=group] button:focus,[role=search] [role=button]:focus,[role=search] [type=button]:focus,[role=search] [type=reset]:focus,[role=search] [type=submit]:focus,[role=search] button:focus{box-shadow:none}}[role=search]>:first-child{border-top-left-radius:5rem;border-bottom-left-radius:5rem}[role=search]>:last-child{border-top-right-radius:5rem;border-bottom-right-radius:5rem}[aria-busy=true]:not(input,select,textarea,html,form){white-space:nowrap}[aria-busy=true]:not(input,select,textarea,html,form)::before{display:inline-block;width:1em;height:1em;background-image:var(--pico-icon-loading);background-size:1em auto;background-repeat:no-repeat;content:"";vertical-align:-.125em}[aria-busy=true]:not(input,select,textarea,html,form):not(:empty)::before{margin-inline-end:calc(var(--pico-spacing) * .5)}[aria-busy=true]:not(input,select,textarea,html,form):empty{text-align:center}[role=button][aria-busy=true],[type=button][aria-busy=true],[type=reset][aria-busy=true],[type=submit][aria-busy=true],a[aria-busy=true],button[aria-busy=true]{pointer-events:none}:host,:root{--pico-scrollbar-width:0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:0;border:0;-webkit-backdrop-filter:var(--pico-modal-overlay-backdrop-filter);backdrop-filter:var(--pico-modal-overlay-backdrop-filter);background-color:var(--pico-modal-overlay-background-color);color:var(--pico-color)}dialog>article{width:100%;max-height:calc(100vh - var(--pico-spacing) * 2);margin:var(--pico-spacing);overflow:auto}@media (min-width:576px){dialog>article{max-width:510px}}@media (min-width:768px){dialog>article{max-width:700px}}dialog>article>header>*{margin-bottom:0}dialog>article>header .close,dialog>article>header :is(a,button)[rel=prev]{margin:0;margin-left:var(--pico-spacing);padding:0;float:right}dialog>article>footer{text-align:right}dialog>article>footer [role=button],dialog>article>footer button{margin-bottom:0}dialog>article>footer [role=button]:not(:first-of-type),dialog>article>footer button:not(:first-of-type){margin-left:calc(var(--pico-spacing) * .5)}dialog>article .close,dialog>article :is(a,button)[rel=prev]{display:block;width:1rem;height:1rem;margin-top:calc(var(--pico-spacing) * -1);margin-bottom:var(--pico-spacing);margin-left:auto;border:none;background-image:var(--pico-icon-close);background-position:center;background-size:auto 1rem;background-repeat:no-repeat;background-color:transparent;opacity:.5;transition:opacity var(--pico-transition)}dialog>article .close:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),dialog>article :is(a,button)[rel=prev]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){opacity:1}dialog:not([open]),dialog[open=false]{display:none}.modal-is-open{padding-right:var(--pico-scrollbar-width,0);overflow:hidden;pointer-events:none;touch-action:none}.modal-is-open dialog{pointer-events:auto;touch-action:auto}:where(.modal-is-opening,.modal-is-closing) dialog,:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-duration:.2s;animation-timing-function:ease-in-out;animation-fill-mode:both}:where(.modal-is-opening,.modal-is-closing) dialog{animation-duration:.8s;animation-name:modal-overlay}:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-delay:.2s;animation-name:modal}.modal-is-closing dialog,.modal-is-closing dialog>article{animation-delay:0s;animation-direction:reverse}@keyframes modal-overlay{from{-webkit-backdrop-filter:none;backdrop-filter:none;background-color:transparent}}@keyframes modal{from{transform:translateY(-100%);opacity:0}}:where(nav li)::before{float:left;content:"​"}nav,nav ul{display:flex}nav{justify-content:space-between;overflow:visible}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--pico-nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--pico-nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--pico-nav-element-spacing-vertical) var(--pico-nav-element-spacing-horizontal)}nav li :where(a,[role=link]){display:inline-block;margin:calc(var(--pico-nav-link-spacing-vertical) * -1) calc(var(--pico-nav-link-spacing-horizontal) * -1);padding:var(--pico-nav-link-spacing-vertical) var(--pico-nav-link-spacing-horizontal);border-radius:var(--pico-border-radius)}nav li :where(a,[role=link]):not(:hover){text-decoration:none}nav li [role=button],nav li [type=button],nav li button,nav li input:not([type=checkbox],[type=radio],[type=range],[type=file]),nav li select{height:auto;margin-right:inherit;margin-bottom:0;margin-left:inherit;padding:calc(var(--pico-nav-link-spacing-vertical) - var(--pico-border-width) * 2) var(--pico-nav-link-spacing-horizontal)}nav[aria-label=breadcrumb]{align-items:center;justify-content:start}nav[aria-label=breadcrumb] ul li:not(:first-child){margin-inline-start:var(--pico-nav-link-spacing-horizontal)}nav[aria-label=breadcrumb] ul li a{margin:calc(var(--pico-nav-link-spacing-vertical) * -1) 0;margin-inline-start:calc(var(--pico-nav-link-spacing-horizontal) * -1)}nav[aria-label=breadcrumb] ul li:not(:last-child)::after{display:inline-block;position:absolute;width:calc(var(--pico-nav-link-spacing-horizontal) * 4);margin:0 calc(var(--pico-nav-link-spacing-horizontal) * -1);content:var(--pico-nav-breadcrumb-divider);color:var(--pico-muted-color);text-align:center;text-decoration:none;white-space:nowrap}nav[aria-label=breadcrumb] a[aria-current]:not([aria-current=false]){background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}aside li,aside nav,aside ol,aside ul{display:block}aside li{padding:calc(var(--pico-nav-element-spacing-vertical) * .5) var(--pico-nav-element-spacing-horizontal)}aside li a{display:block}aside li [role=button]{margin:inherit}[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:.5rem;margin-bottom:calc(var(--pico-spacing) * .5);overflow:hidden;border:0;border-radius:var(--pico-border-radius);background-color:var(--pico-progress-background-color);color:var(--pico-progress-color)}progress::-webkit-progress-bar{border-radius:var(--pico-border-radius);background:0 0}progress[value]::-webkit-progress-value{background-color:var(--pico-progress-color);-webkit-transition:inline-size var(--pico-transition);transition:inline-size var(--pico-transition)}progress::-moz-progress-bar{background-color:var(--pico-progress-color)}@media (prefers-reduced-motion:no-preference){progress:indeterminate{background:var(--pico-progress-background-color) linear-gradient(to right,var(--pico-progress-color) 30%,var(--pico-progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion:no-preference){[dir=rtl] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input,[role=button]){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip]::after,[data-tooltip]::before,[data-tooltip][data-placement=top]::after,[data-tooltip][data-placement=top]::before{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%,-.25rem);border-radius:var(--pico-border-radius);background:var(--pico-tooltip-background-color);content:attr(data-tooltip);color:var(--pico-tooltip-color);font-style:normal;font-weight:var(--pico-font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip]::after,[data-tooltip][data-placement=top]::after{padding:0;transform:translate(-50%,0);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--pico-tooltip-background-color)}[data-tooltip][data-placement=bottom]::after,[data-tooltip][data-placement=bottom]::before{top:100%;bottom:auto;transform:translate(-50%,.25rem)}[data-tooltip][data-placement=bottom]:after{transform:translate(-50%,-.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement=left]::after,[data-tooltip][data-placement=left]::before{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-.25rem,-50%)}[data-tooltip][data-placement=left]:after{transform:translate(.3rem,-50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement=right]::after,[data-tooltip][data-placement=right]::before{top:50%;right:auto;bottom:auto;left:100%;transform:translate(.25rem,-50%)}[data-tooltip][data-placement=right]:after{transform:translate(-.3rem,-50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{opacity:1}@media (hover:hover) and (pointer:fine){[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{--pico-tooltip-slide-to:translate(-50%, -0.25rem);transform:translate(-50%,.75rem);animation-duration:.2s;animation-fill-mode:forwards;animation-name:tooltip-slide;opacity:0}[data-tooltip]:focus::after,[data-tooltip]:hover::after{--pico-tooltip-caret-slide-to:translate(-50%, 0rem);transform:translate(-50%,-.25rem);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover::after,[data-tooltip][data-placement=bottom]:hover::before{--pico-tooltip-slide-to:translate(-50%, 0.25rem);transform:translate(-50%,-.75rem);animation-name:tooltip-slide}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover::after{--pico-tooltip-caret-slide-to:translate(-50%, -0.3rem);transform:translate(-50%,-.5rem);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:focus::before,[data-tooltip][data-placement=left]:hover::after,[data-tooltip][data-placement=left]:hover::before{--pico-tooltip-slide-to:translate(-0.25rem, -50%);transform:translate(.75rem,-50%);animation-name:tooltip-slide}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:hover::after{--pico-tooltip-caret-slide-to:translate(0.3rem, -50%);transform:translate(.05rem,-50%);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:focus::before,[data-tooltip][data-placement=right]:hover::after,[data-tooltip][data-placement=right]:hover::before{--pico-tooltip-slide-to:translate(0.25rem, -50%);transform:translate(-.75rem,-50%);animation-name:tooltip-slide}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:hover::after{--pico-tooltip-caret-slide-to:translate(-0.3rem, -50%);transform:translate(-.05rem,-50%);animation-name:tooltip-caret-slide}}@keyframes tooltip-slide{to{transform:var(--pico-tooltip-slide-to);opacity:1}}@keyframes tooltip-caret-slide{50%{opacity:0}to{transform:var(--pico-tooltip-caret-slide-to);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled=true],[disabled]{cursor:not-allowed}[aria-hidden=false][hidden]{display:initial}[aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}[tabindex],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation}[dir=rtl]{direction:rtl}@media (prefers-reduced-motion:reduce){:not([aria-busy=true]),:not([aria-busy=true])::after,:not([aria-busy=true])::before{background-attachment:initial!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important}} \ No newline at end of file diff --git a/_site/contact/index.html b/_site/contact/index.html deleted file mode 100644 index e59d160..0000000 --- a/_site/contact/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - Contact - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
- -
-
-

Contact

-

I'd love to hear from you!

-
- - Whether you have a project in mind, have feedback on my content, want to learn - more about my services or just feel like chatting about data integration. -
- - -
-
-
-
- - - - diff --git a/_site/index.html b/_site/index.html deleted file mode 100644 index 8d96915..0000000 --- a/_site/index.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
-

Hi, I'm Adam Tetz!

-

I help businesses run more efficiently by bridging the gap between their -data and the actions they take.

-

I achieve this in two key ways:

-
    -
  • -

    First, I automate processes that involve multiple systems, eliminating manual errors, delays and repetitive tasks. This directly reduces your operating costs and minimises risks.

    -
  • -
  • -

    Second, I help gather clear and actionable insights derived from data across different systems. This empowers you to make smarter decisions that improve your organisation's performance.

    -
  • -
-

Beyond data

-

🌍 Adapting to La Vie Française

-

Only just emigrated to France in October 2024, I'm adapting to my living my life in Burgundy and currently learning French (A2 and counting!).

-

⛰️ Outdoors

-

I love the outdoors! Whether it's Hiking, cycling, motoring or just walking une promenade

-

Let’s talk about how we can improve your business with data driven solutions!

- -
-
-
-
- - - - diff --git a/_site/posts/Integration-sandbox intro/index.html b/_site/posts/Integration-sandbox intro/index.html deleted file mode 100644 index 79b34e3..0000000 --- a/_site/posts/Integration-sandbox intro/index.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - I built a sandbox to test integration platforms. - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
- -
-

- I built a sandbox to test integration platforms. -

-

September 5, 2025

-
-

Say you're in the market for a new integration solution and you want to try a few out before committing. Nearly every platform offers demos or trials. But what then? How are you going to decide whether to fully invest (time, money, training) based on a limited trial experience that may not reflect real-world usage?

-

In my experience working with clients, demos are polished to look good, but nothing beats hands-on experience. For trials to succeed you need something meaningful to test. Setting up proper test environments often requires at least VPN access, permissions for other environments or cloud services and IT approvals. This can be challenging and time consuming. So it's tempting to fall back on 'foo', 'bar' examples or the Pokemon API. But will this paint a clear enough picture?

-

The integration sandbox

-

This challenge has led me to build an integration sandbox. The sandbox provides the mock endpoints to test against, so I can test integration flows immediately. My goal was to evaluate how platforms handle common integration patterns:

-
    -
  • Receiving and sending messages via APIs/webhooks
  • -
  • Data transformation and mapping
  • -
  • Conditional routing
  • -
  • Batch processing
  • -
  • Scheduling
  • -
  • Error handling
  • -
  • Authentication
  • -
-

By testing these features I expect to gain insight into a platform's general usability:

-
    -
  • Learning Curve: How quickly can someone become productive?
  • -
  • Developer Experience: How pleasant is the platform for day-to-day work? Think of debugging, data mapping, error messages, documentation.
  • -
  • Implementation Speed: Time from trial start to working integration.
  • -
  • Security Basics: Authentication handling, endpoint security, secrets management
  • -
-

Note: This leaves out performance and scalability. Any serious performance testing would require enterprise-scale infrastructure and realistic data volumes beyond this evaluation's scope.

-

Use case

-

To test these features in a real world (but somewhat simplified) example, I thought of a use case in Transport and Logistics. Specifically the integration between a Shipper and a Broker.

-

Imagine you are a Shipper with a TMS that needs to send orders to a Carrier. The Carrier requires all communication to go through their preferred Broker (visibility platform). -The integration platform sits in the middle, translating the TMS data to the Broker and vice versa.

-
-	sequenceDiagram
-	participant TMS as TMS / Shipper
-	participant IP as Integration platform
-	participant VP as Broker / Visibility platform
-	
-	box transparent Sandbox
-	participant TMS
-	end
-	box transparent Sandbox
-	participant VP
-	end
-
-	TMS->>IP: New shipment
-	IP->>VP: Create order
-	VP->>IP: New event
-	IP->>TMS: Create event
-
-

The sandbox mocks both the TMS and Broker ends of the integration use case and has REST API endpoints to authenticate, seed, trigger, get and create either TMS shipments or Broker events. It's the job of the integrator to make both mock systems work together. Here's an example of a process flow that you can integrate:

-
-flowchart TD
-A@{ shape: circle, label: "start" } --> B
-B@{ shape: rect, label: "get new shipments" } --> C
-subgraph for each shipment
-	C@{shape: lean-r, label: "transform to order"} --> D
-	D@{shape: rect, label: "post order"} --> E
-	E@{shape: rect, label: "log result"}
-end
-E --> F@{shape: diam, label: "success?"}
-		F --> |Yes| G@{shape: framed-circle, label: "End"}
-		F --> |No| H@{shape: rect, label: "Handle errors"}
- 
-
-
    -
  1. Scheduler starts the process
  2. -
  3. Get new shipments from the /tms/shipments endpoint
  4. -
  5. Split shipments payload into a sequence of single shipments (for each) -
      -
    1. Perform a data mapping to the broker format
    2. -
    3. Create the order with the /broker/order endpoint
    4. -
    5. Log the result
    6. -
    -
  6. -
  7. Check the aggregated results for errors and handle if necessary.
  8. -
-

Technical

-

I designed the sandbox with simplicity in mind. It should also be easy to maintain and test for a single developer. I wanted to run it in a container and have the possibility to deploy and use it anywhere. At this stage I'm not really concerned about high performance.

-

The mock APIs are built with Python and FastAPI. I chose FastAPI because it goes hand in hand with Pydantic dataclasses and has a complete set of features like security, easy serialisation and deserialisation of json and the automatic generation of swagger docs. The TMS and Broker endpoints both use different JSON payloads that are generated using the Faker library. The generated data is saved in a SQLite database so that I can later validate the incoming transformations against a set of business rules. Users will get a corresponding HTTP response code with the result of their requests. If something fails users get detailed error messages.

-

Get started

-

Want to try it yourself? The sandbox is available as a Docker image: -docker run -d -p 8000:8000 atetz/integration-sandbox:latest

-

Once running, you can access the API documentation at http://localhost:8000/docs and start building your integration flows immediately. The mapping specifications can be found in the repo! -I also have it running in AWS Lightsail with minimal effort.

-

What's next?

-

In the next weeks I'm going to put it to the test with Fluxygen, Azure Logic Apps and n8n.

-

What do you think? I'd love to hear your thoughts, experiences, or even just a quick hello!

- -
-
-
-
- - - - diff --git a/_site/posts/mra-beeline/index.html b/_site/posts/mra-beeline/index.html deleted file mode 100644 index 1c2c139..0000000 --- a/_site/posts/mra-beeline/index.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - How I used a MyRouteApp GPX with my Beeline moto II - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
- -
-

- How I used a MyRouteApp GPX with my Beeline moto II -

-

May 28, 2025

-
-
- In a hurry? Click here for a TLDR -

While testing out my new Beeline Moto II motorbike navigation, I ran into some compatibility issues with my routes created with MyRouteApp. Namely, losing the turn-by-turn navigation while going off track. My short roadside frustration turned into a deep dive into GPX files and how to integrate the MyRouteApp format with my Beeline. Upon inspecting both files, I noticed a difference in the GPX file structure. Since a GPX is defined in XML, I decided to make a tool in vanilla JavaScript and XSL that will transform the file for me. And since there are other users with the same issue, I thought it would be nice to share my solution and make it available to anyone that can benefit from it. You can find the tool here

-
-

Intro

-

Triumph Bonneville T120One of my favourite ways to enjoy the French outdoors is by riding my motorbike. -I make it a sport to create a twisty route with nice elevations and new viewpoints that preferably pass a couple of picnic spots along the way. My preferred method was creating a route in MyRouteApp and using my QuadLock mounted phone for navigation. And this worked quite well.

-

But, I wanted a more minimalistic device in my cockpit and I liked the idea of having my phone in my pocket instead of on my bike in case of an emergency. -So after some "very deep research" on YouTube and Google, I naturally found (or was influenced towards...) the Beeline Moto II.

-

Fast forward to unboxing and using the Beeline. I was super hyped. I exported my GPX file from MyRouteApp and hit the road. And all went surprisingly well.

-

Problem

-

Beeline device without navigationUntil.... I hit into a familiar yellow French sign named déviation (a diversion)! As soon as I got off the track, my Beeline showed a white arrow further diving into a black abyss. No roads were visible, no directions, only a white arrow and a dotted line showing how far I was off the track.

-

What on earth? Why is my newest piece of navigation technology not navigating? So I stopped, grabbed my phone and opened the Beeline app. Skipping a waypoint wasn't an option because I only had 1 waypoint. Hmm... I opened my maps app and after memorizing some villages I got back on track and my turn by turn navigation was restored. Sweet!

-

On my way home my inner problem solver was already working. Did I export my file wrong? Did I forget to check a box on importing?

-

Soon I learned that other users had similar issues combining MyRouteApp and Beeline, and that their forum topics hit a dead end. They noted that their route seemed to be converted to a track, and only had a start- and end-point. I also learned that it was impossible to import a Beeline GPX in the MyRouteApp. I tried a couple of things on the MyRouteApp end without success. Then on the Beeline support page I found an article on importing and exporting a GPX with this note:

-
Please note: you can only edit GPX-imported routes within the Beeline app if you are using the "Waypoints only" import mode. You can learn more about that mode in the article listed above. -
- — Beeline support -
-
-

Waypoints only import mode? I didn't see that option at all! But surely my GPX had waypoints? During the creation of my route I added 30 or so...

-

You might be thinking: Why aren't you using the Beeline app anyway? While the Beeline app comes with a route creation functionality, I find the feature set of MyRouteApp superior. I want to skip dirt roads, maximize twisty roads, maximize elevation, toggle different points of interest along the way like petrol stations etc.

-

Carrying on with my problem, I created a small test route in the Beeline app and exported a GPX file. Since the GPX file is actually a XML file, I shouldn't have any trouble figuring out what the differences are.

-

This is a snippet of the Beeline GPX export without the XML declaration and namespaces:

-
.....
-<!-- The route waypoints -->
-  <wpt lat="47.765573749816014" lon="4.5727777081385605"/>
-  <wpt lat="47.76747611439015" lon="4.570651287011771"/>
-  <wpt lat="47.84947693295322" lon="4.568749244689883"/>
-  .....
-  <!-- The route -->
-  <rte>
-    <rtept lat="47.76591" lon="4.57288"/>
-    <rtept lat="47.76595" lon="4.5726"/>
-    <rtept lat="47.76597" lon="4.57253"/>
-    <rtept lat="47.766" lon="4.57248"/>
-    <rtept lat="47.76614" lon="4.57222"/>
-    .....
-
-

Alright, now let's have a look at the MyRouteApp GPX that I'm importing:

-
.....
-<rte>
-        <name>test</name>
-        <rtept lat="47.767945375567" lon="4.5705699920654">
-            <name>12 Route de la Jonction, 21400 Nod-sur-Seine, Frankrijk</name>
-            <extensions>
-                <trp:ViaPoint />
-            </extensions>
-        </rtept>
-        ......
-    </rte>
-    <trk>
-        <name>Track-test</name>
-        <trkseg>
-            <trkpt lon="4.570600" lat="47.767940" />
-            <trkpt lon="4.570710" lat="47.768370" />
-            <trkpt lon="4.570720" lat="47.768510" />
-            <trkpt lon="4.570710" lat="47.768550" />
-            <trkpt lon="4.570710" lat="47.768600" />
-.....
-
-

A few things are going on here:

-
    -
  • The Beeline GPX has waypoint <wpt> nodes while the MyRouteApp has not.
  • -
  • The MyRouteApp GPX provides more information in the route segment <rte>.
  • -
  • The MyRouteApp GPX has a track segment <trk>.
  • -
  • The Beeline GPX <rte> segment suspiciously looks a lot like the MyRouteApp <trkseg> because the coordinates are very close to each-other.
  • -
-

Both seem to have a different interpretation of the GPX 1.1 Schema Documentation. Looking at the definitions I note 3 things:

-
    -
  • wptType wpt represents a waypoint, point of interest, or named feature on a map.
  • -
  • rteType rte represents route - an ordered list of waypoints representing a series of turn points leading to a destination.
  • -
  • trkType trk represents a track - an ordered list of points describing a path.
  • -
-

Given the definitions and examples above. I find that the Beeline app should be using the rteType instead of individual waypoints for a route. Because that is what it's designed for. Also, the trkType is meant for tracks and it seems Beeline is using rteType for that.

-

As a good user, I obviously raised a ticket with Beeline, providing as much details as possible. I was then gracefully thanked for my suggestions and informed that my feedback was forwarded up the chain. Great! But knowing that technical feedback like this often gets dismissed as subjective interpretation rather than standards compliance, I knew I had to work on a solution in the meantime.

-

Solution

-

Knowing the differences between the formats, the workaround was relatively straightforward: I only had to transform the MyRouteApp GPX to a Beeline GPX. To make my MyRouteApp GPX compatible with the Beeline app I decided to:

-
    -
  • transform the MyRouteApp <rtept> nodes to <wpt> nodes.
  • -
  • transform the MyRouteApp <trkseg> to a <rte>.
  • -
-

My first test file was hacked together using some good old copy, paste search and replaces.

-

Et voila! Upon importing my newly created GPX I was greeted by another option: "Points de cheminement uniquem...". -Which translates to the "Waypoints only import mode" mentioned by Beeline above. -Phone screenshot -P.S. Pardon my French, I set my phone to French as a part of my language learning process.

-

Sound great? There's just one caveat

-

This methods imports the waypoints added in the MyRouteApp but will re-calculate the route in between them. If you want the Beeline to calculate the same or near similar route, I advise you to take an extra 15 min to add waypoints on every main road change. My approach looked like this:

-

MRA screenshot

-

Automated solution

-

Obviously I wasn't planning on manually editing GPX files every time I wanted to use one of my routes. -So I decided to make a tool that will transform the file for me. And since there are other users with the same issue, I thought it would be nice to share my solution and make it available to anyone that can benefit from it. The solution is simple:

-
    -
  • A small webform takes a GPX file as input and let's the user download the transformed result.
  • -
  • The transformation is done by a script written in JavaScript that executes a XSLT (eXtensible Stylesheet Language Transformations). For those unfamiliar but curious: Check out this Introduction on XSLT.
  • -
  • This all runs within the users browser. Which means I only have to host the static files and don't need worry about running a service.
  • -
-

You can find the result here

-

Thats it!

-

My short road side frustration turned into a deep dive into GPX files and how to integrate the MyRouteApp format with my Beeline. While I hope that Beeline will eventually improve their compatibility, in the meantime my tool will provide a practical solution. If you're facing similar issues, give the tool a try and let me know how it works for your routes. Happy riding!

- -
-
-
-
- - - - diff --git a/_site/posts/webdesign/index.html b/_site/posts/webdesign/index.html deleted file mode 100644 index 7f3fb98..0000000 --- a/_site/posts/webdesign/index.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - How did I make this page? - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
- -
-

- How did I make this page? -

-

May 26, 2025

-
-

My goal was to make a simple page that would enable me to write something about myself and what I do. And it should also be a spot where I could share my ideas. I heard about Github pages before and I wanted to give it a go. Naturally I found loads of resources naming jekyll.

-

I spun up a repo and tried it out with a simple theme. Soon I noticed that once I wanted to make some changes to the theme, it required some effort to understand and override what the previous designer intended. Should I just have picked something and call it a day? Maybe.

-

But there was also a feeling lingering. I wanted something more minimalistic.... -When I was a teenager my "hobby" used to be making websites. Designing a template in a graphic program, slicing it up in 1px images and using HTML + CSS2. -Nowadays we have HTML5 and CSS3. I heard great stories about grid and flexbox. Which meant the days of fighting <div> are long gone..

-

So I decided I'd roll my own. With the help of some useful libraries/tools:

-
    -
  • PicoCSS for a out of the box CSS that gives me a nice set of defaults to work with
  • -
  • 11ty as a simple static site generator so that I can generate content based on Markdown files.
  • -
  • Font Awesome for the flat icons.
  • -
- -
-
-
-
- - - - diff --git a/_site/sitemap.xml b/_site/sitemap.xml deleted file mode 100644 index dbc12f8..0000000 --- a/_site/sitemap.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - / - 2025-04-23T13:34:49.210Z - - - - /blog/ - 2025-05-21T16:00:02.563Z - - - - /contact/ - 2025-05-23T18:07:35.483Z - - - - /approach/ - 2025-05-23T19:19:47.549Z - - - - /posts/webdesign/ - 2025-05-26T00:00:00.000Z - - - - /posts/mra-beeline/ - 2025-05-28T00:00:00.000Z - - - - /utils/myrouteapp-to-beeline/ - 2025-05-28T12:49:23.310Z - - - - /posts/Integration-sandbox intro/ - 2025-09-05T00:00:00.000Z - - - \ No newline at end of file diff --git a/_site/utils/myrouteapp-to-beeline/index.html b/_site/utils/myrouteapp-to-beeline/index.html deleted file mode 100644 index 26a640f..0000000 --- a/_site/utils/myrouteapp-to-beeline/index.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - MyRouteApp to Beeline converter - - - - - - - - - -
-
- - - -
-
- -
-
- -
-
- -
-

MyRouteApp to Beeline converter

-

- This tool will convert a MyRouteApp gpx (version 1.1) file to a gpx that is - compatible with the Beeline moto. -

- - Select your MyRouteApp file - -
- -
- -

Sound great? There's one caveat!

-

- This methods imports the waypoints added in the MyRouteApp but - will re-calculate the route in between them. If you want the Beeline - to calculate the same or near similar route, I advise you to take an extra - 15 min to add waypoints on every main road change. My approach looked like - this: -
- MRA screenshot -

-
- -
-
-
-
- - - - diff --git a/_src/_includes/base.njk b/_src/_includes/base.njk index 7bd356a..b218609 100644 --- a/_src/_includes/base.njk +++ b/_src/_includes/base.njk @@ -14,6 +14,7 @@ type="application/atom+xml" title="{{ metadata.title }}" /> + diff --git a/_src/assets/examples/Sandbox.postman_collection.json b/_src/assets/examples/Sandbox.postman_collection.json new file mode 100644 index 0000000..6eafe69 --- /dev/null +++ b/_src/assets/examples/Sandbox.postman_collection.json @@ -0,0 +1,398 @@ +{ + "info": { + "_postman_id": "2495b31b-7597-4ef2-bbb5-cdba9252c522", + "name": "Integration sandbox", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "24502593" + }, + "item": [ + { + "name": "/token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const responseJson = pm.response.json();", + "if(typeof responseJson.access_token !== 'undefined'){", + " pm.environment.set(\"oauth_token\", responseJson.access_token);", + "}" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "username", + "value": "{{username}}", + "type": "text" + }, + { + "key": "password", + "value": "{{password}}", + "type": "text" + } + ] + }, + "url": { + "raw": "{{base_url}}/token", + "host": ["{{base_url}}"], + "path": ["token"] + } + }, + "response": [] + }, + { + "name": "/api/v1/tms/shipments/seed", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\"count\":50}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/tms/shipments/seed", + "host": ["{{base_url}}"], + "path": ["api", "v1", "tms", "shipments", "seed"] + } + }, + "response": [] + }, + { + "name": "/api/v1/tms/shipments", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"external_reference\": null,\n \"mode\": \"FTL\",\n \"equipment_type\": \"CONTAINER\",\n \"loading_meters\": 10.42,\n \"customer\": {\n \"id\": \"90e7aadf-7322-4a6c-bed8-a3eab1c975d8\",\n \"name\": \"Mcdonald LLC\",\n \"carrier\": \"Barron-Murillo Transport\"\n },\n \"line_items\": [\n {\n \"package_type\": \"CYLINDER\",\n \"stackable\": false,\n \"height\": 106.53,\n \"length\": 128.59,\n \"width\": 186.17,\n \"length_unit\": \"CM\",\n \"package_weight\": 5617.8,\n \"weight_unit\": \"KG\",\n \"description\": \"Decorative concrete pavers for landscaping projects\",\n \"total_packages\": 1\n }\n ],\n \"stops\": [\n {\n \"type\": \"PICKUP\",\n \"location\": {\n \"code\": \"LOC-1026\",\n \"name\": \"Tintzmann\",\n \"address\": {\n \"address\": \"Schomberstr. 25\",\n \"city\": \"Badoberan\",\n \"postal_code\": \"38483\",\n \"country\": \"DE\"\n },\n \"latitude\": -69.8687305,\n \"longitude\": 49.494473\n },\n \"planned_date\": \"2025-09-21\",\n \"planned_time_window_start\": \"06:00:00\",\n \"planned_time_window_end\": \"17:00:00\"\n },\n {\n \"type\": \"DELIVERY\",\n \"location\": {\n \"code\": \"LOC-3814\",\n \"name\": \"Fernandes\",\n \"address\": {\n \"address\": \"avenue Louise Leclerc\",\n \"city\": \"Duval\",\n \"postal_code\": \"91504\",\n \"country\": \"FR\"\n },\n \"latitude\": 2.5878425,\n \"longitude\": 12.782888\n },\n \"planned_date\": \"2025-09-24\",\n \"planned_time_window_start\": \"06:00:00\",\n \"planned_time_window_end\": \"17:00:00\"\n }\n ],\n \"timeline_events\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/tms/shipments", + "host": ["{{base_url}}"], + "path": ["api", "v1", "tms", "shipments"] + } + }, + "response": [] + }, + { + "name": "/api/v1/tms/event/shipment_id", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"external_order_reference\": \"ORD-83747\",\n \"created_at\": \"2025-09-17T15:34:07.241914\",\n \"event_type\": \"PICKED_UP\",\n \"occured_at\": \"2025-09-17T16:30:07.241914\",\n \"source\": \"broker\",\n \"location\": {\n \"code\": \"LOC-7330\",\n \"latitude\": 77.665144,\n \"longitude\": 31.449173\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/tms/event/406d5324-d0ba-46c4-9eb9-e19bc6c3e151", + "host": ["{{base_url}}"], + "path": [ + "api", + "v1", + "tms", + "event", + "406d5324-d0ba-46c4-9eb9-e19bc6c3e151" + ] + } + }, + "response": [] + }, + { + "name": "/api/v1/tms/shipments", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{base_url}}/api/v1/tms/shipments", + "host": ["{{base_url}}"], + "path": ["api", "v1", "tms", "shipments"], + "query": [ + { + "key": "", + "value": "67f055d4-25fe-47ef-a7cf-4c369c406a05", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "/api/v1/tms/shipments/new", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{base_url}}/api/v1/tms/shipments/new?id=xyz", + "host": ["{{base_url}}"], + "path": ["api", "v1", "tms", "shipments", "new"], + "query": [ + { + "key": "id", + "value": "xyz" + } + ] + } + }, + "response": [] + }, + { + "name": "/api/v1/broker/events/seed", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"event\": \"ORDER_LOADED\",\n \"shipment_ids\":[\"406d5324-d0ba-46c4-9eb9-e19bc6c3e151\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/broker/events/seed", + "host": ["{{base_url}}"], + "path": ["api", "v1", "broker", "events", "seed"] + } + }, + "response": [] + }, + { + "name": "/api/v1/broker/events/new", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{base_url}}/api/v1/broker/events/new", + "host": ["{{base_url}}"], + "path": ["api", "v1", "broker", "events", "new"] + } + }, + "response": [] + }, + { + "name": "/api/v1/broker/events", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{base_url}}/api/v1/broker/events", + "host": ["{{base_url}}"], + "path": ["api", "v1", "broker", "events"] + } + }, + "response": [] + }, + { + "name": "/api/v1/broker/events", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"d40109bf-c27a-44a7-86ed-cbf0a45a40dc\",\n \"shipmentId\": \"2d75c319-ead4-4655-96d4-c9188b470c3b\",\n \"dateTransmission\": \"2025-09-16T03:44:55.399999\",\n \"owner\": \"Adam's logistics\",\n \"order\": {\n \"reference\": \"ORD-87217\",\n \"eta\": \"2025-09-25T03:16:32.736037\"\n },\n \"situation\": {\n \"event\": \"DRIVING_TO_LOAD\",\n \"registrationDate\": \"2025-09-16T13:26:00.596158\",\n \"actualDate\": \"2025-09-16T12:53:00.596158\",\n \"position\": {\n \"locationReference\": \"LOC-1026\",\n \"latitude\": 9.6860825,\n \"longitude\": -118.172914\n }\n },\n \"carrier\": \"Barron-Murillo Transport\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/broker/events", + "host": ["{{base_url}}"], + "path": ["api", "v1", "broker", "events"] + } + }, + "response": [] + }, + { + "name": "/api/v1/broker/order", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"shipment\": {\n \"reference\": \"406d5324-d0ba-46c4-9eb9-e19bc6c3e151\",\n \"carrier\": \"Hogan Ltd Transport\",\n \"transportMode\": \"ROAD\",\n \"orders\": [\n {\n \"reference\": \"406d5324-d0ba-46c4-9eb9-e19bc6c3e151\",\n \"handlingUnits\": [\n {\n \"grossWeight\": 7902.35,\n \"width\": 114.17,\n \"length\": 15.17,\n \"packagingQualifier\": \"BX\",\n \"height\": 35.82\n },\n {\n \"grossWeight\": 7902.35,\n \"width\": 114.17,\n \"length\": 15.17,\n \"packagingQualifier\": \"BX\",\n \"height\": 35.82\n },\n {\n \"grossWeight\": 7902.35,\n \"width\": 114.17,\n \"length\": 15.17,\n \"packagingQualifier\": \"BX\",\n \"height\": 35.82\n },\n {\n \"grossWeight\": 6086.55,\n \"width\": 181.15,\n \"length\": 63.67,\n \"packagingQualifier\": \"BL\",\n \"height\": 191.5\n },\n {\n \"grossWeight\": 6086.55,\n \"width\": 181.15,\n \"length\": 63.67,\n \"packagingQualifier\": \"BL\",\n \"height\": 191.5\n },\n {\n \"grossWeight\": 6086.55,\n \"width\": 181.15,\n \"length\": 63.67,\n \"packagingQualifier\": \"BL\",\n \"height\": 191.5\n },\n {\n \"grossWeight\": 11870.4,\n \"width\": 45.82,\n \"length\": 48.92,\n \"packagingQualifier\": \"PL\",\n \"height\": 23.45\n },\n {\n \"grossWeight\": 11870.4,\n \"width\": 45.82,\n \"length\": 48.92,\n \"packagingQualifier\": \"PL\",\n \"height\": 23.45\n },\n {\n \"grossWeight\": 11870.4,\n \"width\": 45.82,\n \"length\": 48.92,\n \"packagingQualifier\": \"PL\",\n \"height\": 23.45\n },\n {\n \"grossWeight\": 11870.4,\n \"width\": 45.82,\n \"length\": 48.92,\n \"packagingQualifier\": \"PL\",\n \"height\": 23.45\n },\n {\n \"grossWeight\": 11870.4,\n \"width\": 45.82,\n \"length\": 48.92,\n \"packagingQualifier\": \"PL\",\n \"height\": 23.45\n },\n {\n \"grossWeight\": 6039.99,\n \"width\": 94.71,\n \"length\": 85.1,\n \"packagingQualifier\": \"CL\",\n \"height\": 107.1\n },\n {\n \"grossWeight\": 6039.99,\n \"width\": 94.71,\n \"length\": 85.1,\n \"packagingQualifier\": \"CL\",\n \"height\": 107.1\n },\n {\n \"grossWeight\": 6039.99,\n \"width\": 94.71,\n \"length\": 85.1,\n \"packagingQualifier\": \"CL\",\n \"height\": 107.1\n },\n {\n \"grossWeight\": 6039.99,\n \"width\": 94.71,\n \"length\": 85.1,\n \"packagingQualifier\": \"CL\",\n \"height\": 107.1\n },\n {\n \"grossWeight\": 6039.99,\n \"width\": 94.71,\n \"length\": 85.1,\n \"packagingQualifier\": \"CL\",\n \"height\": 107.1\n },\n {\n \"grossWeight\": 6708.94,\n \"width\": 138.39,\n \"length\": 127.12,\n \"packagingQualifier\": \"CR\",\n \"height\": 155.31\n },\n {\n \"grossWeight\": 6708.94,\n \"width\": 138.39,\n \"length\": 127.12,\n \"packagingQualifier\": \"CR\",\n \"height\": 155.31\n },\n {\n \"grossWeight\": 6708.94,\n \"width\": 138.39,\n \"length\": 127.12,\n \"packagingQualifier\": \"CR\",\n \"height\": 155.31\n },\n {\n \"grossWeight\": 4789.97,\n \"width\": 162.83,\n \"length\": 171.45,\n \"packagingQualifier\": \"BX\",\n \"height\": 25.47\n },\n {\n \"grossWeight\": 4789.97,\n \"width\": 162.83,\n \"length\": 171.45,\n \"packagingQualifier\": \"BX\",\n \"height\": 25.47\n },\n {\n \"grossWeight\": 9690.5,\n \"width\": 62.17,\n \"length\": 98.91,\n \"packagingQualifier\": \"CL\",\n \"height\": 37.81\n },\n {\n \"grossWeight\": 9690.5,\n \"width\": 62.17,\n \"length\": 98.91,\n \"packagingQualifier\": \"CL\",\n \"height\": 37.81\n },\n {\n \"grossWeight\": 9690.5,\n \"width\": 62.17,\n \"length\": 98.91,\n \"packagingQualifier\": \"CL\",\n \"height\": 37.81\n },\n {\n \"grossWeight\": 1381.8,\n \"width\": 125.64,\n \"length\": 45.47,\n \"packagingQualifier\": \"CR\",\n \"height\": 45.85\n },\n {\n \"grossWeight\": 1381.8,\n \"width\": 125.64,\n \"length\": 45.47,\n \"packagingQualifier\": \"CR\",\n \"height\": 45.85\n },\n {\n \"grossWeight\": 1381.8,\n \"width\": 125.64,\n \"length\": 45.47,\n \"packagingQualifier\": \"CR\",\n \"height\": 45.85\n },\n {\n \"grossWeight\": 1381.8,\n \"width\": 125.64,\n \"length\": 45.47,\n \"packagingQualifier\": \"CR\",\n \"height\": 45.85\n },\n {\n \"grossWeight\": 8348.63,\n \"width\": 92.22,\n \"length\": 109.12,\n \"packagingQualifier\": \"BL\",\n \"height\": 51.84\n },\n {\n \"grossWeight\": 8348.63,\n \"width\": 92.22,\n \"length\": 109.12,\n \"packagingQualifier\": \"BL\",\n \"height\": 51.84\n },\n {\n \"grossWeight\": 8348.63,\n \"width\": 92.22,\n \"length\": 109.12,\n \"packagingQualifier\": \"BL\",\n \"height\": 51.84\n },\n {\n \"grossWeight\": 3013.5,\n \"width\": 39.85,\n \"length\": 148.6,\n \"packagingQualifier\": \"OT\",\n \"height\": 131.3\n },\n {\n \"grossWeight\": 3013.5,\n \"width\": 39.85,\n \"length\": 148.6,\n \"packagingQualifier\": \"OT\",\n \"height\": 131.3\n },\n {\n \"grossWeight\": 3013.5,\n \"width\": 39.85,\n \"length\": 148.6,\n \"packagingQualifier\": \"OT\",\n \"height\": 131.3\n },\n {\n \"grossWeight\": 3013.5,\n \"width\": 39.85,\n \"length\": 148.6,\n \"packagingQualifier\": \"OT\",\n \"height\": 131.3\n }\n ],\n \"consignee\": {\n \"country\": \"DE\",\n \"identification\": \"LOC-9004\",\n \"city\": \"Hannover\",\n \"address1\": \"Segebahnstraße 76\",\n \"postalCode\": \"11666\",\n \"latitude\": 44.7743115,\n \"name\": \"Mühle GmbH\",\n \"dates\": [\n {\n \"dateTime\": \"2025-09-25T06:00:00\",\n \"qualifier\": \"PERIOD_EARLIEST\"\n },\n {\n \"dateTime\": \"2025-09-25T17:00:00\",\n \"qualifier\": \"PERIOD_LATEST\"\n }\n ],\n \"longitude\": -160.097804\n },\n \"quantity\": {\n \"grossWeight\": 232924,\n \"loadingMeters\": 10.7\n },\n \"pickUp\": {\n \"country\": \"IT\",\n \"identification\": \"LOC-7330\",\n \"city\": \"Cascina Restelli\",\n \"address1\": \"Strada Laura, 0\",\n \"postalCode\": \"19013\",\n \"latitude\": -26.2330645,\n \"name\": \"Cibin-Chindamo e figli\",\n \"dates\": [\n {\n \"dateTime\": \"2025-09-21T06:00:00\",\n \"qualifier\": \"PERIOD_EARLIEST\"\n },\n {\n \"dateTime\": \"2025-09-21T17:00:00\",\n \"qualifier\": \"PERIOD_LATEST\"\n }\n ],\n \"longitude\": 77.534203\n },\n \"goodsDescription\": \"Commercial grade floor mats for high-traffic areas|Aluminum extrusions for window frame manufacturing|Heavy-duty truck tires, new and retreaded options|Commercial grade carpet tiles for office spaces|Bulk toilet paper for institutional facilities|Fiberglass panels for building exteriors|Liquid soap concentrate in plastic containers|Commercial grade carpet cleaning equipment|Bulk vegetable oil for food service industry|Industrial paper rolls for packaging applications\"\n }\n ]\n },\n \"meta\": {\n \"messageReference\": \"20250917114116375856375856375856-FTL\",\n \"senderId\": \"Adam's Logistics\",\n \"messageDate\": \"2025-09-17T11:41:16\",\n \"messageFunction\": 9\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/broker/order", + "host": ["{{base_url}}"], + "path": ["api", "v1", "broker", "order"] + } + }, + "response": [] + }, + { + "name": "/api/v1/trigger/shipments", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"target_url\": \"{{target_url}}\",\n \"count\": 1\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/trigger/shipments", + "host": ["{{base_url}}"], + "path": ["api", "v1", "trigger", "shipments"] + } + }, + "response": [] + }, + { + "name": "/api/v1/trigger/events", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"target_url\": \"{{target_url}}\",\n \"event\": \"DRIVING_TO_LOAD\",\n \"shipment_ids\": [\n \"861e550e-1bb5-4ffb-82e1-baa15e5b3b9b\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/api/v1/trigger/events", + "host": ["{{base_url}}"], + "path": ["api", "v1", "trigger", "events"] + } + }, + "response": [] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{oauth_token}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [""] + } + } + ] +} diff --git a/_src/assets/examples/xml2json-single-item-array.json b/_src/assets/examples/xml2json-single-item-array.json new file mode 100644 index 0000000..72d1e2c --- /dev/null +++ b/_src/assets/examples/xml2json-single-item-array.json @@ -0,0 +1,119 @@ +{ + "shipment": { + "reference": "ce18ec96-61b5-43f3-91cd-148e1d82f5d2", + "carrier": "Cole Ltd Transport", + "transportMode": "ROAD", + "orders": { + "reference": "ce18ec96-61b5-43f3-91cd-148e1d82f5d2", + "handlingUnits": [ + { + "grossWeight": 7069.62, + "width": 20.88, + "length": 138.51, + "packagingQualifier": "BL", + "height": 115.15 + }, + { + "grossWeight": 7069.62, + "width": 20.88, + "length": 138.51, + "packagingQualifier": "BL", + "height": 115.15 + }, + { + "grossWeight": 7069.62, + "width": 20.88, + "length": 138.51, + "packagingQualifier": "BL", + "height": 115.15 + }, + { + "grossWeight": 7069.62, + "width": 20.88, + "length": 138.51, + "packagingQualifier": "BL", + "height": 115.15 + }, + { + "grossWeight": 2336.24, + "width": 162.91, + "length": 71.51, + "packagingQualifier": "CY", + "height": 31.16 + }, + { + "grossWeight": 890.43, + "width": 95.14, + "length": 111.34, + "packagingQualifier": "CY", + "height": 66.97 + }, + { + "grossWeight": 890.43, + "width": 95.14, + "length": 111.34, + "packagingQualifier": "CY", + "height": 66.97 + }, + { + "grossWeight": 890.43, + "width": 95.14, + "length": 111.34, + "packagingQualifier": "CY", + "height": 66.97 + } + ], + "consignee": { + "country": "GB", + "identification": "LOC-8521", + "city": "Leonardtown", + "address1": "Studio 6\nGill courts", + "postalCode": "WA7 6JT", + "latitude": 13.042235, + "name": "Williams-Patel", + "dates": [ + { + "dateTime": "2025-07-24T06:00:00", + "qualifier": "PERIOD_EARLIEST" + }, + { + "dateTime": "2025-07-24T17:00:00", + "qualifier": "PERIOD_LATEST" + } + ], + "longitude": -168.601537 + }, + "quantity": { + "grossWeight": 10296.29, + "loadingMeters": 14.8 + }, + "pickUp": { + "country": "IT", + "identification": "LOC-9973", + "city": "Riva", + "address1": "Borgo Buonauro, 27 Piano 6", + "postalCode": 81046, + "latitude": 9.223782, + "name": "Scamarcio e figli", + "dates": [ + { + "dateTime": "2025-07-22T06:00:00", + "qualifier": "PERIOD_EARLIEST" + }, + { + "dateTime": "2025-07-22T17:00:00", + "qualifier": "PERIOD_LATEST" + } + ], + "longitude": 123.12346 + }, + "goodsDescription": "Commercial grade floor mats for high-traffic areas|Heavy-duty truck tires, new and retreaded options|Industrial conveyor belt sections" + } + }, + "meta": { + "messageReference": "20250909213726948438948438948438-LTL", + "senderId": "Adam's Logistics", + "messageDate": "2025-09-09T21:37:26", + "messageFunction": 9 + } +} diff --git a/_src/assets/images/fluxygen-sandbox/broker-event-in-1-overview.png b/_src/assets/images/fluxygen-sandbox/broker-event-in-1-overview.png new file mode 100644 index 0000000..07aa2b2 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/broker-event-in-1-overview.png differ diff --git a/_src/assets/images/fluxygen-sandbox/broker-event-in-2-inboundhttps.png b/_src/assets/images/fluxygen-sandbox/broker-event-in-2-inboundhttps.png new file mode 100644 index 0000000..6081025 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/broker-event-in-2-inboundhttps.png differ diff --git a/_src/assets/images/fluxygen-sandbox/fluxygen-homescreen.png b/_src/assets/images/fluxygen-sandbox/fluxygen-homescreen.png new file mode 100644 index 0000000..9928657 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/fluxygen-homescreen.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-1-overview.png b/_src/assets/images/fluxygen-sandbox/get-token-1-overview.png new file mode 100644 index 0000000..08a2538 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-1-overview.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-10-details.png b/_src/assets/images/fluxygen-sandbox/get-token-10-details.png new file mode 100644 index 0000000..ac7e16c Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-10-details.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-11-transactions.png b/_src/assets/images/fluxygen-sandbox/get-token-11-transactions.png new file mode 100644 index 0000000..262d648 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-11-transactions.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-12-transactions-expanded.png b/_src/assets/images/fluxygen-sandbox/get-token-12-transactions-expanded.png new file mode 100644 index 0000000..2176068 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-12-transactions-expanded.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-13-tenant-variables.png b/_src/assets/images/fluxygen-sandbox/get-token-13-tenant-variables.png new file mode 100644 index 0000000..d37f8df Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-13-tenant-variables.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-2-flow-properties.png b/_src/assets/images/fluxygen-sandbox/get-token-2-flow-properties.png new file mode 100644 index 0000000..22194ee Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-2-flow-properties.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-3-scheduler.png b/_src/assets/images/fluxygen-sandbox/get-token-3-scheduler.png new file mode 100644 index 0000000..135d271 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-3-scheduler.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-4-setheaders.png b/_src/assets/images/fluxygen-sandbox/get-token-4-setheaders.png new file mode 100644 index 0000000..b20a437 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-4-setheaders.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-5-setBody.png b/_src/assets/images/fluxygen-sandbox/get-token-5-setBody.png new file mode 100644 index 0000000..2b9a432 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-5-setBody.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-6-http.png b/_src/assets/images/fluxygen-sandbox/get-token-6-http.png new file mode 100644 index 0000000..219154e Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-6-http.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-7-content-router.png b/_src/assets/images/fluxygen-sandbox/get-token-7-content-router.png new file mode 100644 index 0000000..6ca8f3e Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-7-content-router.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-8-set-tenant-var.png b/_src/assets/images/fluxygen-sandbox/get-token-8-set-tenant-var.png new file mode 100644 index 0000000..1ddff81 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-8-set-tenant-var.png differ diff --git a/_src/assets/images/fluxygen-sandbox/get-token-9-installed.png b/_src/assets/images/fluxygen-sandbox/get-token-9-installed.png new file mode 100644 index 0000000..0c7c4b8 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/get-token-9-installed.png differ diff --git a/_src/assets/images/fluxygen-sandbox/mapforce-mapping-overview.png b/_src/assets/images/fluxygen-sandbox/mapforce-mapping-overview.png new file mode 100644 index 0000000..87143e6 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/mapforce-mapping-overview.png differ diff --git a/_src/assets/images/fluxygen-sandbox/shipment-to-broker-1-overview.png b/_src/assets/images/fluxygen-sandbox/shipment-to-broker-1-overview.png new file mode 100644 index 0000000..6dc67be Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/shipment-to-broker-1-overview.png differ diff --git a/_src/assets/images/fluxygen-sandbox/shipment-to-broker-2-aggregated-split.png b/_src/assets/images/fluxygen-sandbox/shipment-to-broker-2-aggregated-split.png new file mode 100644 index 0000000..2c5de59 Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/shipment-to-broker-2-aggregated-split.png differ diff --git a/_src/assets/images/fluxygen-sandbox/shipment-to-broker-3-tracing.png b/_src/assets/images/fluxygen-sandbox/shipment-to-broker-3-tracing.png new file mode 100644 index 0000000..c896f0a Binary files /dev/null and b/_src/assets/images/fluxygen-sandbox/shipment-to-broker-3-tracing.png differ diff --git a/_src/assets/xslt/fluxygen-broker-to-shipment-event.xslt b/_src/assets/xslt/fluxygen-broker-to-shipment-event.xslt new file mode 100644 index 0000000..97ecb3a --- /dev/null +++ b/_src/assets/xslt/fluxygen-broker-to-shipment-event.xslt @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_src/assets/xslt/fluxygen-shipment-to-broker-order.xslt b/_src/assets/xslt/fluxygen-shipment-to-broker-order.xslt new file mode 100644 index 0000000..db2a012 --- /dev/null +++ b/_src/assets/xslt/fluxygen-shipment-to-broker-order.xslt @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_src/css/main.css b/_src/css/main.css index 286c270..0faac5c 100644 --- a/_src/css/main.css +++ b/_src/css/main.css @@ -148,3 +148,10 @@ pre.mermaid { padding: 1rem; /* adjust as needed */ font-family: inherit; /* removes monospace font if you don't want it */ } + +code[class*="language-"], +pre[class*="language-"] code { + font-size: 0.8rem !important; + white-space: pre-wrap !important; + word-break: break-word !important; +} diff --git a/_src/posts/sandbox-fluxygen.md b/_src/posts/sandbox-fluxygen.md new file mode 100644 index 0000000..3dbe5b2 --- /dev/null +++ b/_src/posts/sandbox-fluxygen.md @@ -0,0 +1,429 @@ +--- +title: TMS to visibility platform integration with Fluxygen +date: 2025-11-16 +--- +## Intro +Recently I wrote about the [integration sandbox](https://github.com/atetz/integration-sandbox) I built that enables me to test and evaluate an integration use case in the transport and logistics domain without actually having to deal with setting up real systems. With the sandbox ready, I wanted to see how it works with a platform I know well: [Fluxygen](https://fluxygen.com/). I've used it professionally for e-commerce, finance, transport and logistics, and manufacturing projects. + +Fluxygen is an opinionated, low-code Integration platform as a service (iPaaS). Opinionated means they abstract a lot of the technical details away. It's designed for organisations looking to develop integrations through an intuitive UI without the need for software developers. This enables tech-savvy domain experts to build integrations themselves and lets organisations focus on the business logic that makes their processes special. Having worked with the platform for multiple years, I can definitely say that they deliver on usability. + +At the same time, integration architecture still requires thinking through data flows, error handling, and business logic. The platform gives you the tools, but doesn't do the thinking for you. + +Under the hood, Fluxygen is built on [Apache Camel](https://camel.apache.org/), the open source integration framework that implements the *[Enterprise Integration Patterns](https://www.enterpriseintegrationpatterns.com/)*. Fluxygen uses these patterns throughout their UI and therefore naturally teaches you a universal integration vocabulary. + +Let's see how it all comes together in Fluxygen! +## Processes walkthrough +There are two processes in the sandbox that I want to integrate: +- TMS shipment to Broker order +- Broker event to TMS event +As mentioned in the docs, the APIs are secured. We'll handle this globally for both the processes. Let's have a look at an overview of the processes that we're going to integrate: +#### Authentication +The sandbox's APIs are secured by *Simple OAuth2 with Password and Bearer* authentication that provides a JWT (JSON Web Token). These tokens expire every 15 minutes, so we'll need to create a process that refreshes these tokens automatically and enables the other processes to run without manual intervention. +
+flowchart TD
+A@{ shape: circle, label: "start \n(every 10min)" } --> B
+B@{ shape: rect, label: "get token" } --> C
+C@{shape: diam, label: "success?"}
+		C --> |Yes| D
+		C --> |No| E@{shape: rect, label: "handle errors"}
+D@{shape: rect, label: "Save JWT"} --> F
+F@{shape: framed-circle, label: "end"}
+ 
+
+1. Scheduler starts the process +2. Get a new token from the /token endpoint +3. Check the result +4. Save JWT or handle the unexpected result + +#### TMS shipment to Broker order +The TMS shipments will be pulled periodically from the TMS API and then transformed and delivered to the Broker API. +
+flowchart TD
+A@{ shape: circle, label: "start" } --> B
+B@{ shape: rect, label: "get new shipments" } --> C0
+C0@{shape: diam, label: "any \nshipments?"}
+		C0 --> |Yes| C
+		C0 --> |No| C2@{shape: framed-circle, label: "end"}
+subgraph for each shipment
+	C@{shape: lean-r, label: "transform to order"} --> D
+	D@{shape: rect, label: "post order"} --> E
+	E@{shape: rect, label: "log result"}
+end
+E --> F@{shape: diam, label: "success?"}
+		F --> |Yes| G@{shape: framed-circle, label: "end"}
+		F --> |No| H@{shape: rect, label: "handle errors"}
+ 
+
+1. Scheduler starts the process +2. Get new shipments from the /tms/shipments endpoint +3. Check for shipments in response +4. Split shipments payload into a sequence of single shipments (for each) + 1. Perform a data mapping to the broker format + 2. Create the order with the /broker/order endpoint + 3. Log the result +5. Check the aggregated results for errors and handle if necessary. + +#### Broker event to TMS event +The broker events are sent to a webhook which will transform and deliver them to the TMS API: +
+flowchart TD
+A@{ shape: circle, label: "start" } --> B
+B@{ shape: rect, label: "check api key" } --> C
+C@{shape: diam, label: "valid?"}
+		C --> |Yes| D
+		C --> |No| E@{shape: rect, label: "return HTTP 401"}
+D@{shape: lean-r, label: "transform to tms event"} --> F
+F@{shape: rect, label: "post event"} --> G
+G@{shape: diam, label: "success?"}
+		G --> |Yes| H@{shape: framed-circle, label: "End"}
+		G --> |No| I@{shape: rect, label: "handle errors"}
+
+1. Inbound HTTP message starts the process +2. The incoming webhook API token is validated. `X-API-KEY` +3. Perform a data mapping to the tms format +4. Create the event with the tms/event/shipment_id endpoint +5. Log the result +## Integrating with Fluxygen +Now that we have laid our groundwork we can actually start integrating. If you want to follow along, you will first have to reach out to [Fluxygen](https://fluxygen.com/schedule-demo/) for a demo account. +### A quick overview +I'm not going to describe all the features in detail here. I think that [Fluxygen's academy](https://academy.fluxygen.com/docs/guides/tutorials/try_it_yourself) provides loads of detailed info. And there's also [Luke Saunders's video of Dovetail](https://youtu.be/qAHk_S3iRb8?si=t_sGuU_pjOK82udv) (the former name of Fluxygen) which describes the basics excellently. + +Nevertheless, I'd still like to explain some core concepts to give some context. +Primarily there are 4 screens that users can work with: +1. Flow manager - Provides high level information of all the flows and lets you view detailed information, such as installation time, errors, successful executions, tracing and logs per flow. +2. Flow designer - The place where flows are created. +3. Tenant manager - Lets admins manage users and global settings. +4. Tenant variables - Create, update and delete global variables. + + +{% gallery "Homescreen" %} +{% galleryImg "/assets/images/fluxygen-sandbox/fluxygen-homescreen.png", "Fluxygen homescreen", 500 %} +{% endgallery %} + + +Integrations in Fluxygen enable messages to flow from point A to point B. This is done by creating flows where users can manage the flow of messages and how they are processed. Processing is orchestrated by adding the right components in the right order. + +Messages have the following structure (just like HTTP messages): +- Headers -  Contains metadata / header data of the message; +- Body  - Contains the entire message (string or binary). +The destination of a message is dependent on the next component in the flow or the settings of the component. + +There are 4 types of variables in Fluxygen: +1. On the message level there are *message headers*. These are the dynamic variables within a flow. For example: if I want to store a result of an http call to a temporary variable, I would use the headers. +2. Messages also have *message properties*. Message properties contain metadata about a message and are only for internal use. These cannot be set. For example BodySize, HeadersSize, timestamp. +3. *Flow properties* are the static variables of a flow. I primarily use these for base URL's, folder paths, flow specific credentials that don't automatically rotate etc. +4. *Tenant variables*. These can be seen as global variables. I primarily use these for storing credentials that are used by multiple flows. +### Building the authentication flow +As mentioned earlier, the sandbox's APIs requires users to authenticate using OAuth. The type of OAuth is a simple password credentials grant that requires the user to send their username and password in a `application/x-www-form-urlencoded` HTTP POST to the API. If all goes well, the user will get a JWT access token that is valid for 15 minutes. + +Since I want to use the access token from multiple flows, I created a new flow called "get token" that retrieves a new token and stores it in the *tenant variables*. Fluxygen lets you install test and production versions of your flows, and each environment can have their own set of flow properties. Because I wanted the API URL, username, and password to be configurable for different environments, I set them up as flow properties instead of hardcoding them. I also set the tracing of the flow to 1 day. This means that I can view a detailed log of the transactions and that this information is kept for 1 day. + + +{% gallery "getTokenOverview" %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-1-overview.png", "Overview of get token flow.", 500 %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-2-flow-properties.png", "Flow properties.", 500 %} +{% endgallery %} + +I chose to schedule the flow for 10 minutes since this will give me 5 minutes to fix any possible issues. After I set the Content-Type and Accept headers, I set the message body to: `username=#{username}&password=#{password}`. Where the `#{variables}` refer to the flow properties. These are added via the blue # sign. The body is then sent to the sandbox's token URL via a HTTP POST using the HTTP component. I enabled *Use error route?* which means that once the HTTP component returns a response code outside of the 200-300 range, It will trigger the error route. + +{% gallery "getTokenDetails" %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-3-scheduler.png", "Scheduler details.", 400 %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-4-setheaders.png", "SetHeaders.", 400 %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-5-setBody.png", "SetBody.", 400 %} +{% endgallery %} + +If all goes well we should get an HTTP response code of 200 with a message body that looks like this: +```json +{ + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzYW5keSIsImV4cCI6MTc1ODQ1MDA1MX0.i3uSNpI84oPJoH7o72gopAuSgsxKCQvA36dj_dj6Nt0", + "token_type": "bearer" +} +``` + +At this point in the flow we know that we only get valid http response codes. `access_token` is the part we are interested in saving to the *tenant variables*, so I set this on a header using JsonPath. JsonPath lets you extract specific values from JSON responses. In this case I can get the access token with: `$.access_token`. + +But sometimes a valid http status does not necessarily mean that the body is exactly how we want it to be. And I surely do not want to save an empty or invalid value to my variables. To catch these kind of differences I added a header to calculate the length of the token. This time using a [simple expression](https://camel.apache.org/components/4.14.x/languages/simple-language.html): `${header.access-token?.length()}`. Simple is a language shipped with Apache Camel that prevents scripting for simpler use cases. + +Next I added a content router that checks if the length of the `access-token-length` header is greater than 0. If so, it will proceed and save the value to the *tenant variables*. Note in the images that I have added the `Bearer ` to the variable. This makes it easier using the value further down the line directly on a `Authorization` header. If not, it stops at a log component. In my example this situation is not handled any further, but this route could for example send a notification or perform some custom handling according to what the business users want to know. + +{% gallery "getTokenDetails" %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-7-content-router.png", "ContentRouter", 400 %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-8-set-tenant-var.png", "SetTenantVars.", 400 %} +{% endgallery %} + + +### Installing and checking the authentication flow +From the flow designer the play icon on the right will let users install a flow in that environment immediately. Once started, the environment will colour green. To check if the flow runs as it should I can quickly navigate to the flow details via the folder icon next to the stop icon. + +{% gallery "getTokenInstalled" %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-9-installed.png", "Installed.", 800 %} +{% endgallery %} + +The flow details show the general stats first. Here we can see the status of the flow, general settings and how many exchanges were completed, pending or failed. The next tab that I use often is the transactions tab. On this tab it's easy to see how many times the flow has executed and also the exact inputs of every component in the flow. Pro tip: Since the tracing only shows the input a component, I like to end a branch of a flow with a log component so that I can see all relevant outputs in the tracing. + +{% gallery "getTokenTransactions" %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-11-transactions.png", "Scheduler details.", 400 %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-12-transactions-expanded.png", "Scheduler details.", 400 %} +{% endgallery %} + + +So far so good! There are no errors and every component seems to have processed how I wanted it to. Let's go to the *tenant variables* screen to check if the flow has saved the access token. + +{% gallery "getTokenTenantVars" %} +{% galleryImg "/assets/images/fluxygen-sandbox/get-token-13-tenant-variables.png", "Tenant variables", 800 %} +{% endgallery %} + + +Perfect! +Since auth is working, we can now start building the TMS shipment to Broker order flow. +### Building the TMS shipment to Broker order flow +As mentioned earlier, we want to process new shipments on a schedule. But before we dive into creating the flow, we need to make sure that there are new shipments in the sandbox. + +We can seed a number of shipments by sending an *authenticated HTTP POST request* to `#{base_url}/api/v1/tms/shipments/seed` with the following body: + +```json +{"count": 100} +``` + +For tasks like these and creating proof of concepts in general, I like to use [Postman](https://www.postman.com/) as my HTTP client. If you're a Postman user then you're in luck, I have exported my collection for [anyone to use](/assets/examples/Sandbox.postman_collection.json). It uses a couple of environment variables and has a small utility script that stores the result of the `/token` call into the variables, which prevents me from copying and pasting the Bearer token every 15min. + +I gave the flow a clear and descriptive name that matches the process: *new tms shipment to broker order*. For this process I don't have a real business requirement for the time schedule so I decided to go with 5 minutes. The scheduler will trigger the flow as soon as it is installed. + +{% gallery "shipmentToBrokerOverview" %} +{% galleryImg "/assets/images/fluxygen-sandbox/shipment-to-broker-1-overview.png", "Shipment to broker overview.", 800 %} +{% endgallery %} + +Over the development of an integration I will have created and tested many iterations in a short period of time. Preferably I install and test after adding each component and keep the feedback loop as short as possible. Fluxygen has built-in versioning and requires me to create a new version after any change. This makes it very easy to switch between versions and revert back if necessary. This is very useful for experimenting with expressions. + +The first priority after the flow triggers is setting the correct credentials for the request. Since the authentication flow already stores the token, I only need to get the right tenant variable and set the value on a header named Authorization. + +With the authentication in place, I perform a HTTP GET request to `{base_url}/api/v1/tms/shipments/new?limit=10`. I've added the `limit=10` query parameter to have a nice small sample to work with. + +Ideally the API returns a list of shipments, but there are cases where there aren't any new shipments to process. To stop the flow when there are no new shipments, I added a filter that checks if the response body isn't null: `${bodyAs(String)} != 'null'` + +Now I can trust that only a list of shipments is passing through the filter, I split the message to process each shipment separately. In this context a split works like a *for each*. I configured the split component with JsonPath `$[*]` and set the *Aggregation* to *JSON*. + +{% gallery "aggregatedSplit" %} +{% galleryImg "/assets/images/fluxygen-sandbox/shipment-to-broker-2-aggregated-split.png", "Aggregated split.", 300 %} +{% endgallery %} + +From that point on all of the components attached to the bottom part of the split component are executed as a sub-process *for each shipment*. The *Aggregation* setting enables me to collect the result of each sub-process. After all shipments have been processed, the aggregated result is sent back to the main process as output of the split component. I can later use this in the main process to check if there were any errors. + +The sub-process transforms the shipment and sends it to the broker API. +One of the things that Fluxygen *unfortunately does not have* is a built in data mapper. Fortunately there are multiple ways to perform a data mapping with some templating or scripting: +- XML files can be transformed with a XSLT +- Scripting with JavaScript or GroovyScript +- Templating with the Velocity templating engine + +To stay in the low-code theme, Fluxygen recommends using [Altova MapForce](https://www.altova.com/MapForce) as a mapping tool. MapForce is a very powerful graphical data mapping tool that supports a wide range of data formats. In this case I'll use it to make an XSLT. + +You might think: *XSLT?! But we have been working with JSON!* That's correct! In integration projects, the tool of choice often depends on who will maintain the mappings: +- Do we want business users to be able to modify mappings themselves (low-code)? +- Are we okay with all changes requiring developer involvement (code)? +This means for this use case that we'll introduce some format conversion overhead for the sake of maintainability. And while this may introduce other challenges, I'll show how I deal with them to make them less painful. + +For the XSLT setup, I first add a *JsonToXMLSimple* component. As the name states, this is a simple component that transforms a JSON body to XML. It has [some quirks](https://academy.fluxygen.com/docs/components/transformations/json_to_xml_simple#array-element-name) but in general I follow this rule: +- For *one-way conversion* (JSON→XML→XSLT), JsonToXMLSimple is fine +- For *two-way-conversion* (JSON→XML→JSON) a typed XML with JsonToXML is better. + +
+ Why? Click here for a detailed explanation!

+ +Take for example the JsonToXMLSimple component with the following input: + +```json +{ + "id": 1, + "name": "Example", + "list": [ + "a", + "b", + "c" + ] +} +``` + +This will result in: +```xml + + + Example + 1 + a + b + c + +``` + +Converting this XML back to JSON, there are a couple of gotchas: + +```json +{ + "name": "Example", + "id": "1", + "list": [ + "a", + "b", + "c" + ] +} +``` +We can see that id has now lost its integer type. + +Let's use the same example, modified slightly to have only a single item in the array: + +```json +{ + "name": "Example", + "id": "1", + "list": "a" +} +``` +The array in list has disappeared! This is because the XML without types has no context of what type the element had before conversion. + +Let's have a look at the JsonToXml which preserves types: +JsonToXml (using the modified input) +```json +{ + "id": 1, + "name": "Example", + "list": [ + "a" + ] +} +``` + +XML result +```xml + + + 1 + Example + + a + + +``` + +With types enabled, the result still has the array and the integer type of id is preserved: +```json +{ + "id": 1, + "name": "Example", + "list": [ + "a" + ] +} +``` +

+
+ +After converting the JSON to XML, I set the *shipmentId* on a header for later use with an XPath expression: `/shipment/id/text()`. Next is the XSLT component where I add my mapping that I created with MapForce. I have uploaded my [shipment mapping](/assets/xslt/fluxygen-shipment-to-broker-order.xslt) and [event mapping](/assets/xslt/fluxygen-broker-to-shipment-event.xslt) for anyone to use. + +I'm not going to explain MapForce in detail, that could be a whole blogpost in itself. If you are interested in this, then by all means let me know! In the meantime, if you want to get an impression of MapForce I strongly recommend checking out [Altova MapForce and Flowforce overview](https://youtu.be/pAg4mSRsPpI?si=o-MG6TfbxnxOzIPu) by Luke Saunders. + +{% gallery "mappingOverview" %} +{% galleryImg "/assets/images/fluxygen-sandbox/mapforce-mapping-overview.png", "MapForce Mapping.", 800 %} +{% endgallery %} + + +I'll briefly explain what's going on in the data mapping (See the full [mapping requirements](https://github.com/atetz/integration-sandbox/blob/main/docs/integrations/tms-to-broker.md) for context). +- **Un-nest line items to handling units** + - Each line_item gets replicated by its total_packages count. So 3 line items with 4, 1, and 3 packages become 8 individual handlingUnits +- **Concatenate goods descriptions** + - Join all line_item descriptions with a pipe separator into a single goodsDescription field +- **Calculate total gross weight** + - Sum the package_weight × total_packages across all line items +- **Filter stops by type** + - Split the stops array into separate pickUp and consignee objects based on the type field (PICKUP vs DELIVERY) +- **Combine date and time fields** + - Merge planned_date with time_window_start/end to create ISO datetime strings +- **Map package types** + - Transform TMS codes to broker codes (BALE -> BL, CYLINDER -> CY, etc.) +- **Generate message metadata** + - Set messageDate to current timestamp + - Use shipment id as messageReference + - Add fixed senderId and messageFunction + +Next, I have added a *XmlToJson* component with type hints set to true. This creates a perfect JSON for our API which is then sent to the `#{base_url}/api/v1/broker/order` endpoint with the *HTTP* component. This time I set the *Use error route?* option to false. This means that all HTTP response codes will be handled by the flow itself and not the dedicated error flow. + +As I mentioned earlier, the result of this sub-process gets aggregated and sent back to the main flow. If I end this sub-process with the result of the API, then the main process will continue with a list of raw API responses (either shipments or error messages). To give the output a uniform structure, I like to add a custom response based on the API result. This makes the aggregated result easier to process: + +```json +[ + { + "shipmentId": 1, + "result":"OK" + }, + { + "shipmentId": 2, + "result": "ERROR", + "details": "detailed error message here." + }, + { + "shipmentId": 3, + "result":"OK" + } +] +``` + +This is done by adding a *content router* after the *HTTP* component. Since I know that the API will return a HTTP 202 on success, I have added the following rule to the content router: +`${header.CamelHttpResponseCode} == 202`. This routes all successful responses to a dedicated branch. I then set the body of that branch to: +```json +{ + "shipmentId": "${header.shipment-id}", + "result":"OK" +} +``` +Here we can see why the shipment Id was set on a header. + +All unsuccessful responses are sent to the otherwise branch. I then set the body of that branch to: +```json +{ + "shipmentId": "${header.shipment-id}", + "result": "ERROR", + "details": ${bodyAs(String)} +} +``` +Because I know that any unsuccessful response will contain an error message in the body, I've included the API's error message in the details field with :`${bodyAs(String)}`. + +In the main flow, the first thing I do after the split component is set a new *breadcrumbId* with the simple expression: `${header.breadcrumbId}-RESULT` The breadcrumbId is a unique id used for tracking messages in the transaction logs. Once a flow starts, all transactions are grouped by this breadcrumbId. + +Since I aggregated my results, I'm not really interested in all the individual transactions and certainly don't want to scroll through all of them before finding my result. Changing this id after the aggregation lets me filter the transaction logs to see only the final aggregated result rather than each individual shipment processing. + +{% gallery "shipmentToBrokerTracing" %} +{% galleryImg "/assets/images/fluxygen-sandbox/shipment-to-broker-3-tracing.png", "Shipment to broker tracing.", 600 %} +{% endgallery %} + +Last thing left in the flow is handling errors. We can add a content-router with the JSONPath expression: `$..[?(@.result == 'ERROR')]` and add whatever error handling logic suits our needs. For example, send a notification, save it to a database or both. + +### Building the Broker event to TMS event flow +If you made it this far then great! I have introduced you to most of the concepts that are needed to build this flow. + +{% gallery "brokerEventIn" %} +{% galleryImg "/assets/images/fluxygen-sandbox/broker-event-in-1-overview.png", "Broker event in overview.", 1000 %} +{% endgallery %} + +This flow starts with an *InboundHttps* component that lets me expose a *public* endpoint for receiving HTTP messages. Next, I used a *content router* that validates the incoming *X-API-KEY* header with a flow property. If the header matches my property, it continues the route. If not, then I return an HTTP 401 by setting a *CamelHTTPResponseCode* header with the value 401. + +Fluxygen's inbound auth is limited to header filtering. It does not come with an identity and access management (IAM) solution out of the box for securing public endpoints (unfortunately this is not rare in our industry). Fortunately, header filtering includes *X-Forwarded-For* and *X-Real-IP* headers that are injected by the platform's reverse proxy, which can't be spoofed by clients. So IP filtering is also possible, just implemented at the application layer instead of the network level. + +If OAuth validation is a hard requirement then you will need an external IAM service like [Keycloak](https://www.keycloak.org/). The rest of the flow is very similar to what I did in the new shipment flow: +- split the array of events in single events while collecting the responses +- transform using xslt and send to the sandbox API +- check the collected responses for potential errors and handle accordingly +## Wrapping up +In this post I walked you through the integration processes available in the [integration sandbox](https://github.com/atetz/integration-sandbox). Then I explained how to implement them in Fluxygen. First I built a scheduled flow that handled getting, transforming and sending new shipments. And I explained why and how I use each component. + +At the end I showed an example of a flow that can receive events. Here I explained that most of the patterns used are similar. If you followed along, we've covered the basics of: +- Scheduling / batch processing +- Receiving and sending messages via APIs/webhooks +- Data transformation and mapping +- Conditional routing +- Error handling +- Authentication + +### What's next? +In the next weeksI'm going to test the sandbox with [Azure Logic Apps](https://azure.microsoft.com/en-us/products/logic-apps/) and [n8n](https://n8n.io). + +What do you think of this kind of content? I'd love to [hear your thoughts](https://data-integration.dev/contact/), experiences, or even just a quick hello! \ No newline at end of file diff --git a/eleventy.config.js b/eleventy.config.js index d2c8ad7..5fd510a 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,6 +1,102 @@ -import { eleventyImageTransformPlugin } from "@11ty/eleventy-img"; +import Image, { eleventyImageTransformPlugin, Util } from "@11ty/eleventy-img"; import eleventyNavigationPlugin from "@11ty/eleventy-navigation"; +import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight"; import sitemap from "@quasibit/eleventy-plugin-sitemap"; +import sharp from "sharp"; + +const DEFAULT_GALLERY_IMAGE_WIDTH = 200; +const LANDSCAPE_LIGHTBOX_IMAGE_WIDTH = 2000; +const PORTRAIT_LIGHTBOX_IMAGE_WIDTH = 720; + +async function galleryImageShortcode( + src, + alt, + previewWidth = DEFAULT_GALLERY_IMAGE_WIDTH +) { + let lightboxImageWidth = LANDSCAPE_LIGHTBOX_IMAGE_WIDTH; + src = Util.normalizeImageSource( + { + input: this.eleventy.directories.input, + inputPath: this.page.inputPath, + }, + src + ); + + const metadata = await sharp(src).metadata(); + + if (metadata.height > metadata.width) { + lightboxImageWidth = PORTRAIT_LIGHTBOX_IMAGE_WIDTH; + } + + const options = { + formats: ["jpeg"], + widths: [previewWidth, lightboxImageWidth], + urlPath: "/img/", + outputDir: this.eleventy.directories.output + "/img/", + }; + + const genMetadata = await Image(src, options); + if (genMetadata.jpeg.length == 1) { + genMetadata.jpeg.splice(0, 0, genMetadata.jpeg[0]); + } + + const output = ` + + ${alt} + + `.replace(/(\r\n|\n|\r)/gm, ""); + return output; +} + +function galleryShortcode(content, name, imgPerCol) { + if (imgPerCol === undefined) { + const nImg = (content.match(/ 1) { + imgPerCol = 3; + } + } + return ` + + +
+ + + Click to open +
+ `.replace(/(\r\n|\n|\r)/gm, ""); +} export default function (eleventyConfig) { eleventyConfig.addFilter("postDate", (dateObj) => { @@ -14,10 +110,23 @@ export default function (eleventyConfig) { eleventyConfig.addPassthroughCopy("_src/assets"); eleventyConfig.addPlugin(eleventyNavigationPlugin); eleventyConfig.addPlugin(eleventyImageTransformPlugin); - eleventyConfig.addPlugin(sitemap, { sitemap: { hostname: "https://data-integration.dev", }, }); + eleventyConfig.addPairedShortcode("gallery", galleryShortcode); + eleventyConfig.addShortcode("galleryImg", galleryImageShortcode); + eleventyConfig.addPassthroughCopy({ + "./node_modules/photoswipe/dist/photoswipe-lightbox.esm.min.js": + "/js/photoswipe/photoswipe-lightbox.esm.min.js", + "./node_modules/photoswipe/dist/photoswipe.esm.min.js": + "/js/photoswipe/photoswipe.esm.min.js", + "./node_modules/photoswipe/dist/photoswipe.css": + "/css/photoswipe/photoswipe.css", + "./node_modules/mermaid/dist": "/js/mermaid", + "./node_modules/prism-themes/themes/prism-material-light.css": + "/css/prism.css", + }); + eleventyConfig.addPlugin(syntaxHighlight); } diff --git a/package.json b/package.json index 85db849..6f218fc 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "@11ty/eleventy": "^3.0.0", "@11ty/eleventy-img": "^6.0.4", "@11ty/eleventy-navigation": "^1.0.4", - "@quasibit/eleventy-plugin-sitemap": "^2.2.0" + "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2", + "@quasibit/eleventy-plugin-sitemap": "^2.2.0", + "mermaid": "^11.12.1", + "photoswipe": "^5.4.4", + "prism-themes": "^1.9.0" }, "scripts": { "build-ghpages": "npx @11ty/eleventy --pathprefix=/atetz.github.io/" diff --git a/yarn.lock b/yarn.lock index 4fe3689..397928f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -77,6 +77,13 @@ debug "^4.4.0" posthtml-match-helper "^2.0.3" +"@11ty/eleventy-plugin-syntaxhighlight@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@11ty/eleventy-plugin-syntaxhighlight/-/eleventy-plugin-syntaxhighlight-5.0.2.tgz#22688060cb05cc25ce1a51cce0f87033aa8b2477" + integrity sha512-T6xVVRDJuHlrFMHbUiZkHjj5o1IlLzZW+1IL9eUsyXFU7rY2ztcYhZew/64vmceFFpQwzuSfxQOXxTJYmKkQ+A== + dependencies: + prismjs "^1.30.0" + "@11ty/eleventy-utils@^1.0.2", "@11ty/eleventy-utils@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@11ty/eleventy-utils/-/eleventy-utils-1.0.3.tgz#fb70305aed2499eba93b7d1d31de045efe3997fa" @@ -168,6 +175,56 @@ rimraf "^5.0.7" slash "^1.0.0" +"@antfu/install-pkg@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz#78fa036be1a6081b5a77a5cf59f50c7752b6ba26" + integrity sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ== + dependencies: + package-manager-detector "^1.3.0" + tinyexec "^1.0.1" + +"@antfu/utils@^9.2.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-9.3.0.tgz#e05e277f788ac3bec771f57a49fb64546bb32374" + integrity sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA== + +"@braintree/sanitize-url@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz#15e19737d946559289b915e5dad3b4c28407735e" + integrity sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw== + +"@chevrotain/cst-dts-gen@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz#5e0863cc57dc45e204ccfee6303225d15d9d4783" + integrity sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ== + dependencies: + "@chevrotain/gast" "11.0.3" + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/gast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/gast/-/gast-11.0.3.tgz#e84d8880323fe8cbe792ef69ce3ffd43a936e818" + integrity sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q== + dependencies: + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/regexp-to-ast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz#11429a81c74a8e6a829271ce02fc66166d56dcdb" + integrity sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA== + +"@chevrotain/types@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-11.0.3.tgz#f8a03914f7b937f594f56eb89312b3b8f1c91848" + integrity sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ== + +"@chevrotain/utils@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-11.0.3.tgz#e39999307b102cff3645ec4f5b3665f5297a2224" + integrity sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ== + "@emnapi/runtime@^1.2.0": version "1.4.3" resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d" @@ -175,6 +232,25 @@ dependencies: tslib "^2.4.0" +"@iconify/types@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@iconify/types/-/types-2.0.0.tgz#ab0e9ea681d6c8a1214f30cd741fe3a20cc57f57" + integrity sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg== + +"@iconify/utils@^3.0.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@iconify/utils/-/utils-3.0.2.tgz#9599607f20690cd3e7a5d2d459af0eb81a89dc2b" + integrity sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ== + dependencies: + "@antfu/install-pkg" "^1.1.0" + "@antfu/utils" "^9.2.0" + "@iconify/types" "^2.0.0" + debug "^4.4.1" + globals "^15.15.0" + kolorist "^1.8.0" + local-pkg "^1.1.1" + mlly "^1.7.4" + "@img/sharp-darwin-arm64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08" @@ -300,6 +376,13 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@mermaid-js/parser@^0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@mermaid-js/parser/-/parser-0.6.3.tgz#3ce92dad2c5d696d29e11e21109c66a7886c824e" + integrity sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA== + dependencies: + langium "3.3.1" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -354,6 +437,221 @@ dependencies: escape-string-regexp "^5.0.0" +"@types/d3-array@*": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.2.tgz#e02151464d02d4a1b44646d0fcdb93faf88fde8c" + integrity sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw== + +"@types/d3-axis@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.6.tgz#e760e5765b8188b1defa32bc8bb6062f81e4c795" + integrity sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-brush@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.6.tgz#c2f4362b045d472e1b186cdbec329ba52bdaee6c" + integrity sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-chord@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.6.tgz#1706ca40cf7ea59a0add8f4456efff8f8775793d" + integrity sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg== + +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-contour@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.6.tgz#9ada3fa9c4d00e3a5093fed0356c7ab929604231" + integrity sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg== + dependencies: + "@types/d3-array" "*" + "@types/geojson" "*" + +"@types/d3-delaunay@*": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz#185c1a80cc807fdda2a3fe960f7c11c4a27952e1" + integrity sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw== + +"@types/d3-dispatch@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz#ef004d8a128046cfce434d17182f834e44ef95b2" + integrity sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA== + +"@types/d3-drag@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02" + integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-dsv@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz#0a351f996dc99b37f4fa58b492c2d1c04e3dac17" + integrity sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g== + +"@types/d3-ease@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-fetch@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz#c04a2b4f23181aa376f30af0283dbc7b3b569980" + integrity sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA== + dependencies: + "@types/d3-dsv" "*" + +"@types/d3-force@*": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.10.tgz#6dc8fc6e1f35704f3b057090beeeb7ac674bff1a" + integrity sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw== + +"@types/d3-format@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.4.tgz#b1e4465644ddb3fdf3a263febb240a6cd616de90" + integrity sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g== + +"@types/d3-geo@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.1.0.tgz#b9e56a079449174f0a2c8684a9a4df3f60522440" + integrity sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ== + dependencies: + "@types/geojson" "*" + +"@types/d3-hierarchy@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz#6023fb3b2d463229f2d680f9ac4b47466f71f17b" + integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg== + +"@types/d3-interpolate@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.1.tgz#f632b380c3aca1dba8e34aa049bcd6a4af23df8a" + integrity sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg== + +"@types/d3-polygon@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz#dfae54a6d35d19e76ac9565bcb32a8e54693189c" + integrity sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA== + +"@types/d3-quadtree@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz#d4740b0fe35b1c58b66e1488f4e7ed02952f570f" + integrity sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg== + +"@types/d3-random@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.3.tgz#ed995c71ecb15e0cd31e22d9d5d23942e3300cfb" + integrity sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ== + +"@types/d3-scale-chromatic@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#dc6d4f9a98376f18ea50bad6c39537f1b5463c39" + integrity sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ== + +"@types/d3-scale@*": + version "4.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.9.tgz#57a2f707242e6fe1de81ad7bfcccaaf606179afb" + integrity sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw== + dependencies: + "@types/d3-time" "*" + +"@types/d3-selection@*": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.11.tgz#bd7a45fc0a8c3167a631675e61bc2ca2b058d4a3" + integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w== + +"@types/d3-shape@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555" + integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time-format@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz#d6bc1e6b6a7db69cccfbbdd4c34b70632d9e9db2" + integrity sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg== + +"@types/d3-time@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f" + integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g== + +"@types/d3-timer@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + +"@types/d3-transition@*": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.9.tgz#1136bc57e9ddb3c390dccc9b5ff3b7d2b8d94706" + integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-zoom@*": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b" + integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== + dependencies: + "@types/d3-interpolate" "*" + "@types/d3-selection" "*" + +"@types/d3@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.3.tgz#d4550a85d08f4978faf0a4c36b848c61eaac07e2" + integrity sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww== + dependencies: + "@types/d3-array" "*" + "@types/d3-axis" "*" + "@types/d3-brush" "*" + "@types/d3-chord" "*" + "@types/d3-color" "*" + "@types/d3-contour" "*" + "@types/d3-delaunay" "*" + "@types/d3-dispatch" "*" + "@types/d3-drag" "*" + "@types/d3-dsv" "*" + "@types/d3-ease" "*" + "@types/d3-fetch" "*" + "@types/d3-force" "*" + "@types/d3-format" "*" + "@types/d3-geo" "*" + "@types/d3-hierarchy" "*" + "@types/d3-interpolate" "*" + "@types/d3-path" "*" + "@types/d3-polygon" "*" + "@types/d3-quadtree" "*" + "@types/d3-random" "*" + "@types/d3-scale" "*" + "@types/d3-scale-chromatic" "*" + "@types/d3-selection" "*" + "@types/d3-shape" "*" + "@types/d3-time" "*" + "@types/d3-time-format" "*" + "@types/d3-timer" "*" + "@types/d3-transition" "*" + "@types/d3-zoom" "*" + +"@types/geojson@*": + version "7946.0.16" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.16.tgz#8ebe53d69efada7044454e3305c19017d97ced2a" + integrity sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg== + "@types/node@*": version "22.15.21" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.21.tgz#196ef14fe20d87f7caf1e7b39832767f9a995b77" @@ -373,6 +671,11 @@ dependencies: "@types/node" "*" +"@types/trusted-types@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + a-sync-waterfall@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7" @@ -390,6 +693,11 @@ acorn@^8.11.0, acorn@^8.11.2, acorn@^8.14.0, acorn@^8.14.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -535,6 +843,25 @@ chardet@^2.0.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-2.1.0.tgz#1007f441a1ae9f9199a4a67f6e978fb0aa9aa3fe" integrity sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA== +chevrotain-allstar@~0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz#b7412755f5d83cc139ab65810cdb00d8db40e6ca" + integrity sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw== + dependencies: + lodash-es "^4.17.21" + +chevrotain@~11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-11.0.3.tgz#88ffc1fb4b5739c715807eaeedbbf200e202fc1b" + integrity sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw== + dependencies: + "@chevrotain/cst-dts-gen" "11.0.3" + "@chevrotain/gast" "11.0.3" + "@chevrotain/regexp-to-ast" "11.0.3" + "@chevrotain/types" "11.0.3" + "@chevrotain/utils" "11.0.3" + lodash-es "4.17.21" + chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" @@ -578,6 +905,11 @@ color@^4.2.3: color-convert "^2.0.1" color-string "^1.9.0" +commander@7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + commander@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" @@ -588,11 +920,40 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +cose-base@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a" + integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg== + dependencies: + layout-base "^1.0.0" + +cose-base@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-2.2.0.tgz#1c395c35b6e10bb83f9769ca8b817d614add5c01" + integrity sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g== + dependencies: + layout-base "^2.0.0" + cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" @@ -602,6 +963,309 @@ cross-spawn@^7.0.3, cross-spawn@^7.0.6: shebang-command "^2.0.0" which "^2.0.1" +cytoscape-cose-bilkent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b" + integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ== + dependencies: + cose-base "^1.0.0" + +cytoscape-fcose@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz#e4d6f6490df4fab58ae9cea9e5c3ab8d7472f471" + integrity sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ== + dependencies: + cose-base "^2.2.0" + +cytoscape@^3.29.3: + version "3.33.1" + resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.33.1.tgz#449e05d104b760af2912ab76482d24c01cdd4c97" + integrity sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ== + +"d3-array@1 - 2": + version "2.12.1" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" + integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== + dependencies: + internmap "^1.0.0" + +"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== + dependencies: + internmap "1 - 2" + +d3-axis@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" + integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== + +d3-brush@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" + integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "3" + d3-transition "3" + +d3-chord@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966" + integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g== + dependencies: + d3-path "1 - 3" + +"d3-color@1 - 3", d3-color@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +d3-contour@4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc" + integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA== + dependencies: + d3-array "^3.2.0" + +d3-delaunay@6: + version "6.0.4" + resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b" + integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A== + dependencies: + delaunator "5" + +"d3-dispatch@1 - 3", d3-dispatch@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3", d3-drag@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +"d3-dsv@1 - 3", d3-dsv@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" + integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== + dependencies: + commander "7" + iconv-lite "0.6" + rw "1" + +"d3-ease@1 - 3", d3-ease@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +d3-fetch@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22" + integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw== + dependencies: + d3-dsv "1 - 3" + +d3-force@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" + integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== + dependencies: + d3-dispatch "1 - 3" + d3-quadtree "1 - 3" + d3-timer "1 - 3" + +"d3-format@1 - 3", d3-format@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +d3-geo@3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.1.tgz#6027cf51246f9b2ebd64f99e01dc7c3364033a4d" + integrity sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q== + dependencies: + d3-array "2.5.0 - 3" + +d3-hierarchy@3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" + integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== + +"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +d3-path@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== + +d3-polygon@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398" + integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg== + +"d3-quadtree@1 - 3", d3-quadtree@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" + integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== + +d3-random@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4" + integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ== + +d3-sankey@^0.12.3: + version "0.12.3" + resolved "https://registry.yarnpkg.com/d3-sankey/-/d3-sankey-0.12.3.tgz#b3c268627bd72e5d80336e8de6acbfec9d15d01d" + integrity sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ== + dependencies: + d3-array "1 - 2" + d3-shape "^1.2.0" + +d3-scale-chromatic@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314" + integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ== + dependencies: + d3-color "1 - 3" + d3-interpolate "1 - 3" + +d3-scale@4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + +"d3-selection@2 - 3", d3-selection@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +d3-shape@3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== + dependencies: + d3-path "^3.1.0" + +d3-shape@^1.2.0: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +"d3-time-format@2 - 4", d3-time-format@4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +"d3-timer@1 - 3", d3-timer@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +"d3-transition@2 - 3", d3-transition@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + +d3-zoom@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + +d3@^7.9.0: + version "7.9.0" + resolved "https://registry.yarnpkg.com/d3/-/d3-7.9.0.tgz#579e7acb3d749caf8860bd1741ae8d371070cd5d" + integrity sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA== + dependencies: + d3-array "3" + d3-axis "3" + d3-brush "3" + d3-chord "3" + d3-color "3" + d3-contour "4" + d3-delaunay "6" + d3-dispatch "3" + d3-drag "3" + d3-dsv "3" + d3-ease "3" + d3-fetch "3" + d3-force "3" + d3-format "3" + d3-geo "3" + d3-hierarchy "3" + d3-interpolate "3" + d3-path "3" + d3-polygon "3" + d3-quadtree "3" + d3-random "3" + d3-scale "4" + d3-scale-chromatic "3" + d3-selection "3" + d3-shape "3" + d3-time "3" + d3-time-format "4" + d3-timer "3" + d3-transition "3" + d3-zoom "3" + +dagre-d3-es@7.0.13: + version "7.0.13" + resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz#acfb4b449f6dcdd48d8ea8081a6d8c59bc8128c3" + integrity sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q== + dependencies: + d3 "^7.9.0" + lodash-es "^4.17.21" + +dayjs@^1.11.18: + version "1.11.19" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938" + integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw== + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -616,6 +1280,20 @@ debug@^4.3.5, debug@^4.3.7, debug@^4.4.0: dependencies: ms "^2.1.3" +debug@^4.4.1: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +delaunator@5: + version "5.0.1" + resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.1.tgz#39032b08053923e924d6094fe2cde1a99cc51278" + integrity sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw== + dependencies: + robust-predicates "^3.0.2" + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -652,6 +1330,13 @@ domhandler@^4.2.0, domhandler@^4.2.2: dependencies: domelementtype "^2.2.0" +dompurify@^3.2.5: + version "3.3.0" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.3.0.tgz#aaaadbb83d87e1c2fbb066452416359e5b62ec97" + integrity sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ== + optionalDependencies: + "@types/trusted-types" "^2.0.7" + domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -760,6 +1445,11 @@ eventemitter3@^4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +exsolve@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.8.tgz#7f5e34da61cd1116deda5136e62292c096f50613" + integrity sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA== + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -852,6 +1542,11 @@ glob@^10.3.7: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" +globals@^15.15.0: + version "15.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" + integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== + graceful-fs@^4.2.11: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -867,6 +1562,11 @@ gray-matter@^4.0.3: section-matter "^1.0.0" strip-bom-string "^1.0.0" +hachure-fill@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/hachure-fill/-/hachure-fill-0.5.2.tgz#d19bc4cc8750a5962b47fb1300557a85fcf934cc" + integrity sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg== + htmlparser2@^7.1.1: version "7.2.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5" @@ -893,6 +1593,13 @@ http-errors@^2.0.0: statuses "2.0.1" toidentifier "1.0.1" +iconv-lite@0.6: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + image-size@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.2.1.tgz#ee118aedfe666db1a6ee12bed5821cde3740276d" @@ -905,6 +1612,16 @@ inherits@2.0.4, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + +internmap@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" + integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== + is-alphabetical@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" @@ -1006,6 +1723,18 @@ junk@^1.0.1: resolved "https://registry.yarnpkg.com/junk/-/junk-1.0.3.tgz#87be63488649cbdca6f53ab39bec9ccd2347f592" integrity sha512-3KF80UaaSSxo8jVnRYtMKNGFOoVPBdkkVPsw+Ad0y4oxKXPduS6G6iHkrf69yJVff/VAaYXkV42rtZ7daJxU3w== +katex@^0.16.22: + version "0.16.25" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.25.tgz#61699984277e3bdb3e89e0e446b83cd0a57d87db" + integrity sha512-woHRUZ/iF23GBP1dkDQMh1QBad9dmr8/PAwNA54VrSOVYgI12MAcE14TqnDdQOdzyEonGzMepYnqBMYdsoAr8Q== + dependencies: + commander "^8.3.0" + +khroma@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.1.0.tgz#45f2ce94ce231a437cf5b63c2e886e6eb42bbbb1" + integrity sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw== + kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -1016,6 +1745,32 @@ kleur@^4.1.5: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +langium@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/langium/-/langium-3.3.1.tgz#da745a40d5ad8ee565090fed52eaee643be4e591" + integrity sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w== + dependencies: + chevrotain "~11.0.3" + chevrotain-allstar "~0.3.0" + vscode-languageserver "~9.0.1" + vscode-languageserver-textdocument "~1.0.11" + vscode-uri "~3.0.8" + +layout-base@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2" + integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg== + +layout-base@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-2.0.1.tgz#d0337913586c90f9c2c075292069f5c2da5dd285" + integrity sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg== + linkify-it@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" @@ -1035,6 +1790,20 @@ list-to-array@^1.1.0: resolved "https://registry.yarnpkg.com/list-to-array/-/list-to-array-1.1.0.tgz#ca7dff640606433cac75cbe8446acd864b15bf6f" integrity sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g== +local-pkg@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.2.tgz#c03d208787126445303f8161619dc701afa4abb5" + integrity sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A== + dependencies: + mlly "^1.7.4" + pkg-types "^2.3.0" + quansync "^0.2.11" + +lodash-es@4.17.21, lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -1057,6 +1826,11 @@ markdown-it@^14.1.0: punycode.js "^2.3.1" uc.micro "^2.1.0" +marked@^16.2.1: + version "16.4.2" + resolved "https://registry.yarnpkg.com/marked/-/marked-16.4.2.tgz#4959a64be6c486f0db7467ead7ce288de54290a3" + integrity sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA== + maximatch@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/maximatch/-/maximatch-0.1.0.tgz#86cd8d6b04c9f307c05a6b9419906d0360fb13a2" @@ -1077,6 +1851,32 @@ merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +mermaid@^11.12.1: + version "11.12.1" + resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-11.12.1.tgz#97445451ce7d0d3740bc2159cb25464bece60b67" + integrity sha512-UlIZrRariB11TY1RtTgUWp65tphtBv4CSq7vyS2ZZ2TgoMjs2nloq+wFqxiwcxlhHUvs7DPGgMjs2aeQxz5h9g== + dependencies: + "@braintree/sanitize-url" "^7.1.1" + "@iconify/utils" "^3.0.1" + "@mermaid-js/parser" "^0.6.3" + "@types/d3" "^7.4.3" + cytoscape "^3.29.3" + cytoscape-cose-bilkent "^4.1.0" + cytoscape-fcose "^2.2.0" + d3 "^7.9.0" + d3-sankey "^0.12.3" + dagre-d3-es "7.0.13" + dayjs "^1.11.18" + dompurify "^3.2.5" + katex "^0.16.22" + khroma "^2.1.0" + lodash-es "^4.17.21" + marked "^16.2.1" + roughjs "^4.6.6" + stylis "^4.3.6" + ts-dedent "^2.2.0" + uuid "^11.1.0" + micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" @@ -1131,6 +1931,16 @@ mkdirp@^3.0.1: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== +mlly@^1.7.4: + version "1.8.0" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.8.0.tgz#e074612b938af8eba1eaf43299cbc89cb72d824e" + integrity sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g== + dependencies: + acorn "^8.15.0" + pathe "^2.0.3" + pkg-types "^1.3.1" + ufo "^1.6.1" + moo@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c" @@ -1206,6 +2016,11 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +package-manager-detector@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/package-manager-detector/-/package-manager-detector-1.5.0.tgz#8dcf7b78554047ddf5da453e6ba07ebc915c507e" + integrity sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw== + parse-srcset@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" @@ -1216,6 +2031,11 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +path-data-parser@0.1.0, path-data-parser@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/path-data-parser/-/path-data-parser-0.1.0.tgz#8f5ba5cc70fc7becb3dcefaea08e2659aba60b8c" + integrity sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w== + path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -1229,6 +2049,16 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +photoswipe@^5.4.4: + version "5.4.4" + resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-5.4.4.tgz#e045dc036453493188d5c8665b0e8f1000ac4d6e" + integrity sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -1239,6 +2069,24 @@ pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== +pkg-types@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.3.0.tgz#037f2c19bd5402966ff6810e32706558cb5b5726" + integrity sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig== + dependencies: + confbox "^0.2.2" + exsolve "^1.0.7" + pathe "^2.0.3" + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -1246,6 +2094,19 @@ please-upgrade-node@^3.2.0: dependencies: semver-compare "^1.0.0" +points-on-curve@0.2.0, points-on-curve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/points-on-curve/-/points-on-curve-0.2.0.tgz#7dbb98c43791859434284761330fa893cb81b4d1" + integrity sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A== + +points-on-path@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/points-on-path/-/points-on-path-0.2.1.tgz#553202b5424c53bed37135b318858eacff85dd52" + integrity sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g== + dependencies: + path-data-parser "0.1.0" + points-on-curve "0.2.0" + posthtml-match-helper@^2.0.2, posthtml-match-helper@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/posthtml-match-helper/-/posthtml-match-helper-2.0.3.tgz#04afcadd3a3306bf0445b6d6ead79d4e4083c6d6" @@ -1273,6 +2134,16 @@ posthtml@^0.16.6: posthtml-parser "^0.11.0" posthtml-render "^3.0.0" +prism-themes@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/prism-themes/-/prism-themes-1.9.0.tgz#19c034f3205f1e28d75d89728e54ccd745f7e3dd" + integrity sha512-tX2AYsehKDw1EORwBps+WhBFKc2kxfoFpQAjxBndbZKr4fRmMkv47XN0BghC/K1qwodB1otbe4oF23vUTFDokw== + +prismjs@^1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" + integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== + promise@^7.0.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -1290,6 +2161,11 @@ punycode.js@^2.3.1: resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== +quansync@^0.2.11: + version "0.2.11" + resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.11.tgz#f9c3adda2e1272e4f8cf3f1457b04cbdb4ee692a" + integrity sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -1326,6 +2202,21 @@ rimraf@^5.0.7: dependencies: glob "^10.3.7" +robust-predicates@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" + integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== + +roughjs@^4.6.6: + version "4.6.6" + resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.6.tgz#1059f49a5e0c80dee541a005b20cc322b222158b" + integrity sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ== + dependencies: + hachure-fill "^0.5.2" + path-data-parser "^0.1.0" + points-on-curve "^0.2.0" + points-on-path "^0.2.1" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -1333,6 +2224,16 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rw@1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" + integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + sax@^1.2.4: version "1.4.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" @@ -1521,6 +2422,16 @@ strip-bom-string@^1.0.0: resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" integrity sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g== +stylis@^4.3.6: + version "4.3.6" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320" + integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== + +tinyexec@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.2.tgz#bdd2737fe2ba40bd6f918ae26642f264b99ca251" + integrity sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -1533,6 +2444,11 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +ts-dedent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" + integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== + tslib@^2.4.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" @@ -1543,6 +2459,11 @@ uc.micro@^2.0.0, uc.micro@^2.1.0: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== +ufo@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + undici-types@~6.21.0: version "6.21.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" @@ -1558,6 +2479,46 @@ urlpattern-polyfill@^10.0.0: resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec" integrity sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg== +uuid@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" + integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== + +vscode-jsonrpc@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9" + integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA== + +vscode-languageserver-protocol@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea" + integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg== + dependencies: + vscode-jsonrpc "8.2.0" + vscode-languageserver-types "3.17.5" + +vscode-languageserver-textdocument@~1.0.11: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== + +vscode-languageserver-types@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a" + integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg== + +vscode-languageserver@~9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz#500aef82097eb94df90d008678b0b6b5f474015b" + integrity sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g== + dependencies: + vscode-languageserver-protocol "3.17.5" + +vscode-uri@~3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" + integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"