From 0988d6fa2570a2015a883c7f5c4e4977cadedabc Mon Sep 17 00:00:00 2001 From: Paulo Borges Date: Mon, 16 Jun 2025 12:59:35 -0300 Subject: [PATCH] add Astro engine to source repo --- docs/.gitignore | 39 + docs/.gitmodules | 32 + docs/README.md | 1 + docs/astro.config.mjs | 246 +++ docs/package.json | 28 + .../clients/grpc/images/consumer-groups.webp | Bin 0 -> 87926 bytes .../clients/grpc/images/duplicate-event.webp | Bin 0 -> 25758 bytes .../client/grpc/images/consumer-groups.webp | Bin 0 -> 87926 bytes .../client/grpc/images/duplicate-event.webp | Bin 0 -> 25758 bytes docs/public/assets/img/favicon.ico | Bin 0 -> 15406 bytes docs/public/assets/img/logo-black.svg | 26 + docs/public/assets/img/logo-plum.svg | 26 + docs/public/assets/img/logo-white.svg | 26 + docs/public/favicon.svg | 1 + docs/sidebars.json | 47 + docs/src/assets/fonts/Solina-Bold.woff2 | Bin 0 -> 16364 bytes docs/src/assets/fonts/Solina-Light.woff2 | Bin 0 -> 16344 bytes docs/src/assets/fonts/Solina-Medium.woff2 | Bin 0 -> 16148 bytes docs/src/assets/fonts/Solina-Regular.woff2 | Bin 0 -> 16312 bytes docs/src/assets/fonts/font-face.css | 31 + docs/src/assets/img/favicon.ico | Bin 0 -> 15406 bytes docs/src/assets/img/logo-black.svg | 26 + docs/src/assets/img/logo-plum.svg | 26 + docs/src/assets/img/logo-white.svg | 26 + docs/src/assets/styles/buttons.css | 30 + docs/src/assets/styles/custom.css | 146 ++ docs/src/assets/styles/global.css | 7 + docs/src/assets/styles/nav-links.css | 51 + docs/src/assets/styles/tailwind-theme.css | 122 ++ docs/src/components/CustomSidebar.astro | 554 ++++++ docs/src/components/ThemeAwareImages.astro | 118 ++ docs/src/components/ThemeSelect.astro | 169 ++ docs/src/components/icons/Moon.astro | 3 + docs/src/components/icons/Sun.astro | 3 + docs/src/content.config.ts | 23 + .../docs/client/grpc/appending-events.mdx | 92 + .../docs/client/grpc/authentication.mdx | 63 + .../docs/client/grpc/delete-stream.mdx | 30 + .../docs/client/grpc/getting-started.mdx | 128 ++ docs/src/content/docs/client/grpc/index.mdx | 9 + .../docs/client/grpc/observability.mdx | 128 ++ .../client/grpc/persistent-subscriptions.mdx | 176 ++ .../content/docs/client/grpc/projections.mdx | 232 +++ .../docs/client/grpc/reading-events.mdx | 146 ++ .../src/content/docs/client/grpc/sidebar.json | 42 + .../docs/client/grpc/subscriptions.mdx | 252 +++ docs/src/content/docs/index.mdx | 30 + docs/src/utils/sidebar.ts | 396 +++++ docs/tools/convert.py | 1564 +++++++++++++++++ docs/tools/generate-sidebars.js | 246 +++ docs/tools/repos-config.json | 201 +++ docs/tools/requirements.txt | 1 + docs/tools/sync-repos.js | 256 +++ docs/tsconfig.json | 5 + 54 files changed, 5804 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/.gitmodules create mode 100644 docs/README.md create mode 100644 docs/astro.config.mjs create mode 100644 docs/package.json create mode 100644 docs/public/assets/img/doc-imgs/client/clients/grpc/images/consumer-groups.webp create mode 100644 docs/public/assets/img/doc-imgs/client/clients/grpc/images/duplicate-event.webp create mode 100644 docs/public/assets/img/doc-imgs/client/grpc/images/consumer-groups.webp create mode 100644 docs/public/assets/img/doc-imgs/client/grpc/images/duplicate-event.webp create mode 100644 docs/public/assets/img/favicon.ico create mode 100644 docs/public/assets/img/logo-black.svg create mode 100644 docs/public/assets/img/logo-plum.svg create mode 100644 docs/public/assets/img/logo-white.svg create mode 100644 docs/public/favicon.svg create mode 100644 docs/sidebars.json create mode 100644 docs/src/assets/fonts/Solina-Bold.woff2 create mode 100644 docs/src/assets/fonts/Solina-Light.woff2 create mode 100644 docs/src/assets/fonts/Solina-Medium.woff2 create mode 100644 docs/src/assets/fonts/Solina-Regular.woff2 create mode 100644 docs/src/assets/fonts/font-face.css create mode 100644 docs/src/assets/img/favicon.ico create mode 100644 docs/src/assets/img/logo-black.svg create mode 100644 docs/src/assets/img/logo-plum.svg create mode 100644 docs/src/assets/img/logo-white.svg create mode 100644 docs/src/assets/styles/buttons.css create mode 100644 docs/src/assets/styles/custom.css create mode 100644 docs/src/assets/styles/global.css create mode 100644 docs/src/assets/styles/nav-links.css create mode 100644 docs/src/assets/styles/tailwind-theme.css create mode 100644 docs/src/components/CustomSidebar.astro create mode 100644 docs/src/components/ThemeAwareImages.astro create mode 100644 docs/src/components/ThemeSelect.astro create mode 100644 docs/src/components/icons/Moon.astro create mode 100644 docs/src/components/icons/Sun.astro create mode 100644 docs/src/content.config.ts create mode 100644 docs/src/content/docs/client/grpc/appending-events.mdx create mode 100644 docs/src/content/docs/client/grpc/authentication.mdx create mode 100644 docs/src/content/docs/client/grpc/delete-stream.mdx create mode 100644 docs/src/content/docs/client/grpc/getting-started.mdx create mode 100644 docs/src/content/docs/client/grpc/index.mdx create mode 100644 docs/src/content/docs/client/grpc/observability.mdx create mode 100644 docs/src/content/docs/client/grpc/persistent-subscriptions.mdx create mode 100644 docs/src/content/docs/client/grpc/projections.mdx create mode 100644 docs/src/content/docs/client/grpc/reading-events.mdx create mode 100644 docs/src/content/docs/client/grpc/sidebar.json create mode 100644 docs/src/content/docs/client/grpc/subscriptions.mdx create mode 100644 docs/src/content/docs/index.mdx create mode 100644 docs/src/utils/sidebar.ts create mode 100644 docs/tools/convert.py create mode 100644 docs/tools/generate-sidebars.js create mode 100644 docs/tools/repos-config.json create mode 100644 docs/tools/requirements.txt create mode 100644 docs/tools/sync-repos.js create mode 100644 docs/tsconfig.json diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..6e27d7c8 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,39 @@ +# build output +dist/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store +tools/.venv/pyvenv.cfg +tools/.venv/Scripts +tools/.venv/Lib/site-packages/setuptools-58.1.0.dist-info +tools/.venv/Lib/site-packages/distutils-precedence.pth +tools/.venv + + +# Generated documentation content +src/content/docs/server/ +src/content/docs/cloud/ +src/content/docs/clients/ +src/content/_samples/ + +# Temp directories +.tmp/ + +# Keep only manually maintained docs +!src/content/docs/manually-maintained/ \ No newline at end of file diff --git a/docs/.gitmodules b/docs/.gitmodules new file mode 100644 index 00000000..5cabddc6 --- /dev/null +++ b/docs/.gitmodules @@ -0,0 +1,32 @@ +[submodule "src/content/docs/server"] + path = src/content/docs/server + url = https://github.com/kurrent-io/KurrentDB.git + branch = master +[submodule "src/content/docs/http-api"] + path = src/content/docs/http-api + url = https://github.com/kurrent-io/KurrentDB.git + branch = master +[submodule "src/content/clients/dotnet"] + path = src/content/clients/dotnet + url = https://github.com/kurrent-io/EventStore-Client-Dotnet.git + branch = release/v23 +[submodule "src/content/clients/java"] + path = src/content/clients/java + url = https://github.com/kurrent-io/KurrentDB-Client-Java.git + branch = trunk +[submodule "src/content/clients/rust"] + path = src/content/clients/rust + url = https://github.com/kurrent-io/KurrentDB-Client-Rust.git + branch = master +[submodule "src/content/clients/node"] + path = src/content/clients/node + url = https://github.com/kurrent-io/KurrentDB-Client-NodeJS.git + branch = master +[submodule "src/content/clients/go"] + path = src/content/clients/go + url = https://github.com/kurrent-io/KurrentDB-Client-Go.git + branch = main +[submodule "src/content/clients/python"] + path = src/content/clients/python + url = https://github.com/pyeventsourcing/kurrentdbclient.git + branch = 1.0 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..e2d97660 --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +Temporary repository that hosts the future docs framework Astro - Starlight diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 00000000..bdb84182 --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,246 @@ +import { defineConfig } from "astro/config"; +import starlight from "@astrojs/starlight"; +import starlightImageZoom from "starlight-image-zoom"; +import tailwindcss from "@tailwindcss/vite"; +import rehypeMermaid from 'rehype-mermaid'; +import logoPlum from "./src/assets/img/logo-plum.svg"; +import logoLight from "./src/assets/img/logo-white.svg"; +import starlightDocSearch from '@astrojs/starlight-docsearch'; +import { loadEnv } from 'vite'; + +const env = loadEnv(process.env.NODE_ENV || 'production', process.cwd(), ''); + +const PUBLIC_ALGOLIA_APPLICATION_ID = process.env.PUBLIC_ALGOLIA_APPLICATION_ID || env.PUBLIC_ALGOLIA_APPLICATION_ID; +const PUBLIC_ALGOLIA_SEARCH_API_KEY = process.env.PUBLIC_ALGOLIA_SEARCH_API_KEY || env.PUBLIC_ALGOLIA_SEARCH_API_KEY; +const PUBLIC_ALGOLIA_INDEX_NAME = process.env.PUBLIC_ALGOLIA_INDEX_NAME || env.PUBLIC_ALGOLIA_INDEX_NAME; + +const isLocal = process.env.NODE_ENV === "development"; + +const plugins = [starlightImageZoom()]; + +if (PUBLIC_ALGOLIA_APPLICATION_ID && PUBLIC_ALGOLIA_SEARCH_API_KEY && PUBLIC_ALGOLIA_INDEX_NAME) { + plugins.push(starlightDocSearch({ + appId: PUBLIC_ALGOLIA_APPLICATION_ID, + apiKey: PUBLIC_ALGOLIA_SEARCH_API_KEY, + indexName: PUBLIC_ALGOLIA_INDEX_NAME, + })); +} + +export default defineConfig({ + integrations: [ + starlight({ + components: { + ThemeSelect: "./src/components/ThemeSelect.astro", + Sidebar: "./src/components/CustomSidebar.astro" + }, + customCss: [ + "./src/assets/styles/global.css", + "./src/assets/styles/custom.css", + "./src/assets/fonts/font-face.css", + "./src/assets/styles/nav-links.css", + ], + favicon: "/assets/img/favicon.ico", + head: [ + { + tag: 'script', + content: ` + (function() { + const theme = localStorage.getItem('starlight-theme') || 'light'; + document.documentElement.setAttribute('data-theme', theme); + })(); + ` + }, + // Add navigation links via JavaScript, to avoid creating a new component + { + tag: 'script', + content: ` + document.addEventListener('DOMContentLoaded', function() { + const header = document.querySelector('.header'); + if (header) { + // Create nav container + const navContainer = document.createElement('nav'); + navContainer.className = 'custom-nav-links'; + + // Define navigation items + const navItems = [ + { label: 'Getting Started', href: '/getting-started/introduction/', pathMatch: '/getting-started/' }, + { label: 'Kurrent Cloud', href: '/cloud/introduction/', pathMatch: '/cloud/' }, + { label: 'KurrentDB', href: '/server/v25.0/quick-start/', pathMatch: '/server/' }, + { label: 'Client & SDKs', href: '/client/grpc/', pathMatch: '/client/' }, + { label: 'Tutorials', href: '/tutorials/auto-scavenge/', pathMatch: '/tutorials/' } + ]; + + // Create nav links + navItems.forEach(item => { + const link = document.createElement('a'); + link.href = item.href; + link.textContent = item.label; + link.className = 'nav-link'; + + // Mark active link + if (window.location.pathname.startsWith(item.pathMatch)) { + link.classList.add('active'); + } + + navContainer.appendChild(link); + }); + + // Insert after logo/site title + const siteTitle = header.querySelector('.site-title'); + if (siteTitle && siteTitle.parentNode) { + siteTitle.parentNode.insertBefore(navContainer, siteTitle.nextSibling); + } + } + }); + ` + }, + ...(!isLocal + ? [ + { + attrs: { + src: "https://secure.businessintuition247.com/js/264384.js", + type: "text/javascript", + }, + tag: "script", + }, + { + content: + '', + tag: "noscript", + }, + { + tag: 'script', + content: ` + setTimeout(() => { + const script = document.createElement('script'); + script.setAttribute('data-blockingmode', 'auto'); + script.setAttribute('data-cbid', 'ee971b30-e872-46e8-b421-706ef26d9dcc'); + script.id = 'Cookiebot'; + script.src = 'https://consent.cookiebot.com/uc.js'; + script.type = 'text/javascript'; + document.head.appendChild(script); + }, 100); + ` + }, + { + tag: 'script', + content: ` + setTimeout(() => { + const script = document.createElement('script'); + script.async = true; + script.id = 'CookieDeclaration'; + script.src = 'https://consent.cookiebot.com/ee971b30-e872-46e8-b421-706ef26d9dcc/cd.js'; + script.type = 'text/javascript'; + document.head.appendChild(script); + }, 150); + ` + }, + { + attrs: { + "data-cookiecategory": "marketing", + src: "https://secure.businessintuition247.com/js/sc/264384.js", + type: "text/plain", + }, + tag: "script", + }, + { + attrs: { + "data-project-color": "#631B3A", + "data-project-logo": logoLight, + "data-project-name": "Kurrent", + "data-project-id": "9ff147dd-2c68-495d-9859-de159901d8c5", + src: "https://widget.kapa.ai/kapa-widget.bundle.js", + }, + tag: "script", + }, + ] + : []), + ], + logo: { + dark: logoLight, + light: logoPlum, + replacesTitle: true, + }, + plugins: plugins, + social: [ + { + href: "https://github.com/kurrent-io", + icon: "github", + label: "GitHub", + }, + ], + title: "Kurrent Documentation", + }), + ], + markdown: { + syntaxHighlight: { + theme: "github-dark", + excludeLangs: ['mermaid'] + }, + rehypePlugins: [ + [rehypeMermaid, { + strategy: 'img-svg', + dark: true, + // Light theme config + mermaidConfig: { + theme: 'base', + themeVariables: { + // Light mode colors + background: '#ffffff', + primaryColor: '#631B3A', + primaryTextColor: '#ffffff', + primaryBorderColor: '#631B3A', + lineColor: '#475569', + textColor: '#1e293b', + mainBkg: '#631B3A', + secondaryColor: '#f8fafc', + tertiaryColor: '#f1f5f9', + + edgeLabelBackground: '#ffc107', + labelTextColor: '#1a1a1a', + + clusterBkg: '#f8f9fa', + clusterBorder: '#6c757d', + + defaultLinkColor: '#6c757d' + } + }, + // Dark theme config + darkMermaidConfig: { + theme: 'base', + themeVariables: { + // Dark mode colors + background: '#1e293b', + primaryColor: '#8b4d6b', + primaryTextColor: '#ffffff', + primaryBorderColor: '#8b4d6b', + lineColor: '#94a3b8', + textColor: '#f1f5f9', + mainBkg: '#8b4d6b', + secondaryColor: '#334155', + tertiaryColor: '#475569', + + edgeLabelBackground: '#f59e0b', + labelTextColor: '#1a1a1a', + + clusterBkg: '#334155', + clusterBorder: '#64748b', + + defaultLinkColor: '#9ca3af' + } + } + }] + ] + }, + vite: { + plugins: [tailwindcss()], + resolve: { + alias: [ + { find: "@grpc/", replacement: "/src/content/_samples/grpc/" }, + { find: "@httpapi/", replacement: "/src/content/_samples/http-api/" }, + { find: "@server/", replacement: "/src/content/_samples/server/" }, + { find: "@/components", replacement: "/src/components" }, + ], + }, + }, +}); \ No newline at end of file diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000..9285693d --- /dev/null +++ b/docs/package.json @@ -0,0 +1,28 @@ +{ + "name": "kurrent-docs", + "type": "module", + "version": "1.0.0", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro", + "sync": "node tools/sync-repos.js", + "convert": "python3 tools/convert.py", + "build-prod": "npm run sync && npm run convert && npm run build" + }, + "dependencies": { + "@astrojs/starlight": "^0.34.3", + "@astrojs/starlight-docsearch": "^0.6.0", + "@astrojs/starlight-tailwind": "^4.0.1", + "@lorenzo_lewis/starlight-utils": "^0.3.2", + "@tailwindcss/vite": "^4.1.4", + "astro": "^5.8.0", + "playwright": "^1.52.0", + "rehype-mermaid": "^3.0.0", + "sharp": "^0.32.5", + "starlight-image-zoom": "^0.12.0", + "tailwindcss": "^4.1.5" + } +} diff --git a/docs/public/assets/img/doc-imgs/client/clients/grpc/images/consumer-groups.webp b/docs/public/assets/img/doc-imgs/client/clients/grpc/images/consumer-groups.webp new file mode 100644 index 0000000000000000000000000000000000000000..a9139ac8e70d43accd6556f43c89e8d07f466faf GIT binary patch literal 87926 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

8&`7Q1}O+{s+T6T5F>Pq&*LVj}n_+Jglo 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 literal 0 HcmV?d00001 diff --git a/docs/public/assets/img/doc-imgs/client/grpc/images/consumer-groups.webp b/docs/public/assets/img/doc-imgs/client/grpc/images/consumer-groups.webp new file mode 100644 index 0000000000000000000000000000000000000000..a9139ac8e70d43accd6556f43c89e8d07f466faf GIT binary patch literal 87926 zcmbrlbzD_jy9P>kNOyyDcQ?}A-5@P3-QC@tf^;K|(j_6?AT8anu3JRi-`!__=iKW* zt{-#7m}9=<9ZwBK2{ADnHDDk$Q6YI%c@9Fu@2?q@p)!G~wqVl0`K;Me#0y@M5tDqr z3F(9nHM6+~qXT?eTF4IVWLTM>8&TtJ;CBK@%%yj%5UO$jV%k#+882=_1H9Z9`5%*S z33fcFO!%|BVebJ)D_501QEDgLb9xaE#gCw09d30wJj@>Gsg5iGnU4eykl)zH39h`q z@sD~tUFSc--gn#q&Q@jt0Koa(i^tptl*cbuh~GM3Ixf7Y04Cpx@1q~06$z$0K6|a) zH2``ZS^$wJ)OQ58V+(qx9mE8SfFbYm%O1eS_b&kSsNFV(3GyKSVKY-M|-Z%bR zK#bl1e=eZ%@$fG5(QJG7fH&$c`%$lkZw-Izq2uxD1~3#I5ZwqEd(@lZug|X50|rzR zTtB1$Qa3nv0C(Q2_Yhu*fUQT%rR;m#N4+C{&PQ&q*N=Sw?>pN7+wGNQz^Ug{gyF9I zo{6A2a_-ci-#D3YX(D)zWUvwytUw|{kuth36`phnEr>E#s=Ovxi4#*!9rXX|?Zz0n z82K&cIeJTM8)dS>+puz}FA={X;Bwfl^#uQy|D;wiE-rrmIFK9lDM-AWd@;^?<{-#j zBI>-%FiQ=itKn>A!N=Lp-RW=T)nO5*1>1G*h zgIPgjE7d|{UKF+IJ0l-%5(@V#j6GlIEtdLq7<}n>(4t?h94v@!xyYi=HYOm#SKXd( zm-D05AS!V^r6Wl%7Q{EFw>Y`@g#GO9W&KM~ClG?IOS)n^uR@sMm-kNDg?I#GY_8N| zTaeb_{9Rf;M2<(lFve+{-n0pD^(S09ihi(y3gdmAO^wI#X`@2tGrlkwx0HQKGb=R* zsqKxGwKqe24N$3BdEF+vM3OBpwuO0*_P@r%7H!|Lv)5^BcVWEhE`}EY4#j)FJQl{3YC=G_dbp@!0wjU9WxN@TM;jk_zXK*x6$s49xV{a8 zrX5gwDolVFhXyRWlfB%ae7H}WsHaKn5+!s66RKueA2?wpjeIlt%VpfAU-M8K1!bxv zdi-nn|4qu6_2C8faLb^6W~bK&V=;mTQ|sNPtk{#lNgt4YE{78}UW@WRfBXDg$PQY$jQ-Fe z$?XDW+ngakv;QkIm8}l4m*&!A&HAjg_7jVFG63u!3;0JMEH}6wI;d9j7)Q4Fy%iJm&eLP*-(C_zJ^Jja4vB-*hg4Xnx=zj(=~f2R8w8E&gzG3 zELls)HYmXrzP=uIr(fQlfHFsFB^uzQ^_c7ry6jDlpm&*fyd@ZVgY+UIQ`t#*Q$N(< zi?4e@imIixkHp1t#rb(5R}Zbd$)mDXZXDw~RM~ysH$o+3)Xmu&=g&*p*dJeawbkgy zWTnEF8Z=3hr4}{oBN?@}^vlWJbKLOih}$h_8Cv{q2^=VKgg-x#Q`#gXT|WN~!fIe% z4m@|dPE(Of&lN=47;z_%lc3PSu0PbOz`9qAf+@H0mI^8eybIRheZW~61#R_A<{6x9 zo>GKu_F3Wv%()qbhLKNcW+;W9+&V6c=pqpwn`K&-fN5n#!{v%J0*Gewqv>@eID-{1 zUB4Lzd?`N6r~Vx53wTP9R&9Xq2=OH#?<4gdkz+Csv&voEY@8{eEW8Cf-7)6JCtdk zCLdVlUHJs#$@Ii*t_)dESTmMCARHUVEhtLS#MD`fjeDboo4xDfwI2RFUAA78A6&=y zfZo|bj-G&!^aL7yk}}=w>W1|9B}dIH_dL2_smwV8t~?Xb<_CNNAculhp^@;$NY4V* z&=;?zYN^wJmFJJ((YK3zz;iL=@7a)2UivV-=hMz-@scm{W0;U0(t zDOQhQO*b>Q7U<09YkI1`iQB&4=*sUgwcY)CAaPa;`ifO4l1H!O4$aUXh`Y!x9+_IR z7tvyj&{B(|e!TNL$SCZ?Osp1$ zWj`l6pmT~Ev;fS9SuJLqucCW@nsBWPmK3L%@dQr1bs_Z>kEKS$zuDaEDu#&K2EvJ- zTw8PIJr#NBGk!QYbQ74vw9NtLafT>m5`OnQl-JH27*=*~itzs@_+spL^*rivVnSF^ zRyM|NqrbK`8h{fs8)t~mxYugyYp&d6M!YPJ~vj;Q2C*hAFHw` z*~r(q5Ayj*{{wmwr}z4~fN4QU927cM=v;p+XIc<4h7eyj+pNF^+#l;2*sLoV9)+{# zLy5`okAWka9#+R$EIorUQq0pU@SpGfXLM#0_Nx`w>hA5ZE()>^P=x;n=AtIKd#7R~ zHTaD)V_~@Pekg=r%Lz9boVqn@mH`akJSJj$*@S*uTkv+FWV4CVpdd&|Dd1x8m528+- zCSG8EIWz1sBk+>s+6uL_bKlIR#Y?q8^hhAfucht!78g+GY|_MgDxVZJ+z8n&i99iv zw0bolq{+>+h<}3~-$Dszz)1|-z`-$zC>w}jAWSC-_w_U93!Un&PbqGx2r~Y6p^gmi zp2}5nJ_Jqrxs?6t!!{w^$$k_?p)YZEvkYB}o9fH<7R@PZDb2`IONDw`3%0`dVpH`c z^GWqMiZl5Ze_VQfQR3Va{eMVfk;LZEv5CFuqpUPK&C%4h=TlLR{ zJTmz~F?m>Qzwl@EAyR&E`0+Rr2JMt)(NZTzEPj6F_W}EGQJTsMjdGI3-mVFiMw^i*f%$=iRP59T=r!`(hs&qwJ_(g8^4=h_m#oR*n0+-wKt4RL%spOc+xq6FQ z87!a-i0~dao^w z%iq*;hAU~`g?O&%c+2bI>9NWy-|D=_cS62>2E{O>x+$1p#)3~x!+2IZva=@hiFlcC zP#(Yx?{3$>`c1!p`$oR?)I_c5H}2S?#jF9-l%)+(+g($5kjx6`HH?WRWsq3X)ZN;A6Cbd+oo;#aUM6|y^?VJM z2Z%_L2*jC`S+zi?1&Z!VRn*U@7A>k3}n%OUZx_n+hrR_K3R z8MbgxMjXqSFFw8bz(5qS;i@l;_35}Xh&gi27tRc)2LyBEc9LH3oyt?YWntKo%c<=^ z$9PqT8{k2crf~{03NH5H`!xF1`YKeA*h-kgL%1l7*zXUc^9gEnmV62LJQkyBN5#6v zQi;uO+?Ir;UkK0HFf^Hl(E4{G+0%$66pKvbhr#%xKPZt9pgs(~b{d=?+xftlZ@sG% zidnv@Y}x(Vte=_#4g2^%e!CL7Fq`ndy#aYhrXjO$7V2lik=Ljs2AY)i=T7REy1e#= z)c)N(wcci4AT7$ATV!XbYxoNs?|;_sKs3JP5sXbm=dN>f4eD&B9N$|I9YetY)R(Pq zzqO*UR%GEn?eEZGGi#=rJ%CpaMuI`OzbCo8tq2CGTa>+&Ztp*ZhKlELVRtqvC z{jTsj$W-HeA?!)uT1hvSUE3WSOZgbK@9`S;zbXtIw=vIaACImb!#y`X50v}}-nde@ z>kAp(6UVM3v1eCvwYU`&LuYWjwq^-^Z4Mrli^IgsS$mqBP|7+{M}~yWQ7)n>9!zOtu*5Di2pn zh5Obb4GlbS>fIg=WwDD-t(x|q{ZhOgUtgIyg!R^&h(vEh5ZzvZyd{Vt4b1tg=dEEL@wT97=xy|{;*;&Z@ zX~Q8DhZuVzx>8Eo$6#94qJp2Xfn3s}(iACKTPdvy;Bk0k1G}2I5SlLs+#;)omFgW{;(o0Y$&6i}EMXi=>lpI^ zq(yDcLkfMRi69rY!A-P-;%1oUaE#LH?JeI?5|0tO9Tzq{hr*tTAG`CL$o~5`q_n`l zH-mqYlQKMgo^cU)I>;L`ghq0qD~@i+RNF5n7qC{Ve&zTRFW}SOGol6aqdDBFwl?Z) z(c&(RO&I13#0#~2Zi4_z!P)gb!bj>F5gBlhysbH=xg*Q(n6nQNl1+=sIGqLqZ{*{N zmMxI0Uls&sJF*zp+*; z#Gqpg|v^0#T*=R3Z`Dnoky>wnQ{Uh zCWdj3G~TB6CODwxYuBsM*J?zM7h9xP4>t@!SyNo$DxulkGLfhf<1->^wU@quc6Kg2 zpgyZEa9q0P{-xAQ@^3w`p{hESQKXpLph6s`szXJq#;QEIzS=T=eQDl4?vg^d6OtK2 zK*;csnWHMsx3>#i#H6^POWAn=gJ%H;G=$ENv^s}S4;Sg^LLLW(#> zwnweTPT%)9=QydK7?79-hnI4J_JpV#EDB4<0zxojk*wL61$4&3crRQ#4q~mUDsGPt zuDNP%Vkja5$KX_MfJ1X51#%_1G=neITGrVP8QSLQ^ys-e9yxT}&GK%_-nji{_r-yoZZBK_6=no;Pr=I0hF?p5L{ zWHWkG92|ZgWnwd9kqO(jmaC1_cLxiH&LNLnIeh3Km+zpdc3Sbo()mHf``ym?sM~_j zRDdU;qU7*DI%kLlfzwvR*lc^XNiMEJED6B8KKUF}{Gt~lIzTA}F(mZg71%UwZl32p z2x5SeZvWznh^&w3aM%5Gn}hk2lr{f7T|{%CryEn0SpGQf6skjKZWOu$N8 zk6!`!)`Co(-9xX{wb|gO&EV*BP3{F5hT9P(vs@-98w50NSldiGxsb7Qq)R~6!;>Z* zX(ne>NK~pZ^>Lq7`d)c^$0_MJw$L)(WSwKPK8)2hf3OK8H8qv$>9(I0(U%!9&U%2 zgfyj`7G^U6&XGDqNgAn(D{Vo#35Z;H%6*t1IonFv>Rt%Mg6LJD65)7<4x6&AN{SU) zeT~Xj{To`=3lCMbkkn~&Xa(S z5S}8ifpB38fKn3Z_*4U0UM+XU!wXZ!E_&=v?S!{zMhwOUpkU_2>XaPVuJ#4?4b5ju zQh=9&AMUlEu?#~S^wsU7J@wYS=OiAvpvDU@R6jZpF$i>_e!oXigY^-t=6uwnS7l1t zLc_)*imF7+Fl}|l|KO$>=oZc&B3G@@>fAyjh(k9an+`S_rb94#!7ey2O;@{9a)z?Z zj?A}8?WIi(?h(F9K=r$x!}D(}wy#5j08ANn#L0K?e#&e-5~+x5CrVD0RgXxmo&_uc z8I_j)=gp$q*L)?Y)iHUf#;r8;uS{!4?|Lcy?-^#NEdsK4G0mn1`axZQG-2y2ckqrq zepD`6A}7D85cmJEK7UD6oukj5L_+&eaqkJ9ut;QJ=uG<)DAt@+eKXpA2VQ3+a3>@aRrYh7B7 z5YSlR0nHc`^TRz+ymil%n+;bJ#L+;fO4Kb^Q0kJ|>x0MmO9QHPY3@BDCD|^1DEvW- zXcqTZm4E9-|2#DmcS&Z?fAwm!A$ zza!GxP1G9iL*S%|?1aE0vy>Kf= z;9~GoM)F@!d-N|v9x{D2)Yi>Vvco65)HXe+nqybrgui3-EWkHhsI? zJR$#S7P%bxT7};rZ6*Jcr4&lT2BdZUhY})T#A#0ET0#XD0(K`t^^?5(n9+aXI4+~p z5{oaMcM+TbsX*?JQ9qt6c?fX%jLE)QBUiJ`)RXDw_~}Yh!w%6DS-2^G98bpoV0xRJ z(n-o>Ed0qlP+%BL({a2L`lYFn2{6=Jf?LxA*}b8C6Txq)q8sq*N%^A0Qt~?g!o@&n z6UGIjiP75V9Ph?odvrOC9i_K(L@G9b^$3tde*^WQN#r@|$L5#x6dWvHKCB1ZbV-=v z_pgxD`DMRxa>#3R1g0ylMu6%nT>K$c1x5(zoYi7I5G6Uf$e_aB6)ie_zv|}7+@q^l zgiS7M_E~Q6*SOrr)?Xx*0Qht2Gc!f8$^a`%IwEMTeX_d^nrN~i&RBo z`>)NbU-zbo>iKrDJg^m^%|z_GTK1z`qO?deASL}6g|WAx z7}S+Iokqs9bP=q?Ql|wJ*=syR8(#PMWQ_Xx7T|RxEqlY28Klb0fxaF}KutwuH<^_0e_7jjXAD&aUl< z(P_-nW+Y}@Sw(<^^1LxT+b~bv>v@PQt+>zfAS~-P5`L|Pt+@+$97g7U=qm|h1bkZy zOc~ZM2?HyW+ARK4b1Bi99mZRc?3dX=1GymlDHl8&{r)&r2KZ{0A)oHOPyUj25Fx$nX5r4q)zY4 z&fS-*T;R<}5*zB^X#h2erfTi_d(b@}(8yO?{UkCyPRnH5MDS19BxPlikown#M{(_jE zth6H9BR+z}+oZmGlHipW_=u52M@aG2TTWnX88Ha;n-QfgMH_a0zf-T3ToPw-nPv9M zyDS9O0~Tt(F0sciBc#2kv|ST$U8HXqr|;X^w|!Vg1DPfeu2w>hB z(Luu7q9d3~b-4)j*m6$EX2SRX7m1|{VeGjv5LxG?imSnjBz`6nqz`@;jDENk2hw22 z8=ba+8syd)MAt{`SwpP#h^x2XLmU%%1YKV^F%(ApCP)~G+NTLb+~CT&k87b=?~=+q ze}_T9efsaWl{vd76Ce04sQ{}|Q0L~bYWa_a!E|YC4Xde{2=TuxoiLmsUdKtU zId*n(6BoX}d;3PCH}Ak7k>c}L1ujSS=Z^EN8vk7)8RZB2#r`M)b6#M54m{B7nD2R) zLLxoZ;!WpNRVIR)Rh0=20t^B4U4Y@0{u~N9$pTs*e}&;1+cL40VN!Le$)jr=zUiHKCq*>Gq z8l7=nYnjWO&G`=UY{uzIkwp=C1|E3h*?&aZ2gP?`LAh)kwvRb6_%>m9z z9%vI$ue?HDQq9uMmf$yC)OZO#Y z=eV`-3lDup=2th|ANI=;P$~rX*^GK2#_C+6U!<9FC#k&f(#0TlHjF|OHSArK);EIs z23J5Jl=qNG!|vD-TBM+hu}4VF?roF4K)F-@N;>}f>o)4!c=jz!{-d_I?7}QaL@OhZ z+#N|Tp1#Ttk2Ql-jv>eE#~1Ue9tMf#bi(V6$U$_MH*yp2c73f_IR`3YhhGtbVv~Qt z6)~}<+6N_*iU1Ar>5W2#TB1XbbVL($(Cy8dpgT6Pnzw-&DaTmk^bM;fEmRsgH9pM+ zdW&l3jUoxYpYUHrDJtXV%+j8UEr-}*Zuvafx}5f~1Wk{1^4%NdywXHbdGrTz}`Aeq+Et z@_iI{oypI6ze06jNiEiNkq_cFaI~SNXJH!$My;ot=J3}7>h^)`)NFR0HIv3hsVNb1 zCJ4TQ*-W24wPWc;ZIXQtzHHA``UNMP2SE0|c_&z@n!Uj$XyGD^PL>bk`kpRw1$b#M}hlUu%D0Kc+OE2F?HO@&A!$%E4#pHIf(4;)*$^R$c=bS%@aX?4yDK zT;djbh#NMTv?Zq5mMrR|M7aFaQ1VLPlz4=yqjv(LB@JQIKg*Z0u|<17k)YUwT{j^4h{YG8syom$I8Y z5Eio0z@1eqpnsuM5{!&Ja@nBG=e_TbC;mIpsnNF@Z1x<=c%hVYPX=0(9!a^N!tdjH zy|siKIAmO1L1me7dh_Vj$`E4aHdhX>5Q5M3B1kl9a8PRwg07~0j7EYTN>uDh;s|O3BkQKI;aufN`k1BOS*K<9ilF{hO2ax zeIdF1dYUFjB(fp1(7dgwW*0-Ru95{iRG=<77F$qedyqKSAw82s=}q>oL|o%=={D9B zpO`+M-;f=r>hL*GxncY&6YN<&v2CoUNNofAmOaM&-LB-VlXh2HmL&GG)Z^$?KH4Ji z??F~mr_aF8IoKBsyQ}GCj-JSrHZ9jYJEe`~A# z_~`a8hSFq9bV-Wba$leV>5?pJngrkUB0=2&xhDF7m87s}c(NRRn+<;|U;gUOyJvE?kBn3JKl~AN_Sfh@W&fI`SyBG?6w5NXo_A+QBXcLh^?Df> zcTpJl!=w#Y-6o$tE6=x*m#-MUzpA^5(|*XW9qw&zo-xR;m?cpk$Mwnau5vo5I3zdWu>I<`$N;of9%PS{lra3Z+5HZbn0W5`b z0)%f@|0=0U0Vl@BB5}r^ooChUpL|Y@ev83kVf&wth)h7B{vNMEIYPq!?#~c74?Q(} zk8cn|Nlef^ina=c8fTdqoOvj&7`aMEU)9HR(|7qQxQ558Hw-Ha% zo`6BqqtDjv+d;o5J9O|bS(h_x*mEl7zIUz6GYq!fBv}bJf|fr}d7(6nb5`8FH#lj! zOP?Ty@1du`Vw8^l7rvF>Q(ZEyF+slN*w3244_%9eiKHVAWcn-l4W1WwYo8X}mV-VM zk^&(i#6P3u$#gw$ipD{Il>TPAnCJ|=csOo`ARXO8U6`({~vt~lBN8S{B#KTZ| z_Bf*ke_<1S^otR*C$w#ip&+;=pcyg3A3(+h)b0;y0k5}=r5K-TrtLh1nPxg&E9#h} z@4NycoeZAHX&$kvc-G65WQE*9oafMzrK!tNDl%dDCRylXdX3voe<~{P&q&O7_-$)O zu~a7nBnQiS@W$Hnbzsd$k5w()3ZU^dQ#d_Z3c3hPi-+vcMJ}-BoZ_{$t6$@IcP2wGkAo;Er*fBRbn#0%WYM_}8#)*qq#r7OJmrCFu|!6$AbuV?+m<89RR!Cd{( z!fu4z%fRrNVjJ;Xgt%3gB@&!{LJk1L#c%!=-xthl+|}W`v;*8X2&XD`Vqp`|?Cbp$ z2n#<5c)N~08510kZoXJQoU}igXNdmqP}Fw;f?bAA)~#ZB5fiZ;_Dd97mHBbBMxW@< z89Jp1C2LbSsQ4~(sCXl+;$_aA>Y54Yh(>frGO0{R>Pb!v)tlV5o zm<`Im1Pbbag(kRYwx5qLIJTTl$pHI46X5JaNd9m9_;^3Qef51~V`%bVs4}C*FB=&z zJ76tZ?n#vTxSj9)P3COJj#)qF|KoXw=OCa1EZG4l9v#}T>~?B7l6vgg41KOI>SbZJu9{1sY&q~|qv0sR^O zhl-oM$b0@wd0r)yU1ZtwUPCgfldHd-cl{R!d{g#4EjGLQoRs-TzE~Ou_tyP+_&#qr zxr~QDU~@*Z&1lg7J&l9cLbRQqRVmjj{1G zA>i*PNBrXfL&Pn9)uJ^omjO@eqmN4oQY@?ZpT+n8R=j|P#(zgB^BiD9-A$GuZA;^e z#&G%ba|La`KtR*mt^FoSWCZ-lrLS-DUrZ29k z5rfVw%v9m{v*;C|kOPd}s$ z737bg3^2V%z9z`B)xFc8Kb+0Pa~|i%Zw=?22Mk{T?eDFlq%paLd=hM3QIK0Fylv^g z!I-Pj&@@$wdoOQl_@WU~oqqx%X&z3eS5vIGD zmw^UU^IZpO;i3%{3f1k(b*bMnQnZbR7*keBC5$1;XGy2a(gWBDY$H1+)y$H_@1D_r zO*(%Oe~#%U2xnqP;Ydz|aeTUJeO2je zEb#9A_C=BR1QTuPuYjrgU9n!TY=G4Tpaw6em&2I^Vr^3d>g}zxhY|n5r@#uD^R1+& zcQg^s-^y(u<6jC-VA8a!`Gx#gHNRo)vmE|6t(2O%;>oc5o{pdh=3;?9bSYNdeL|}# zk}kD36p83DPvr!32;Z)wzi;R|nhhth^Q3X&YQlQ?Y~?3nbbFwYE#m&)XDAFWsE0B* z+pEZ}k#^W5^2iJ6yoi=%M>(MZ1Vef7auxfWz*$)dLrctlmvq)>tyi!qyIs*(eU(|b zNcHvW-tfL4wT;%v1%?|DXgf!Zk}Ft3e-Eo_!1xlIrL-jdo{ZaTY(+(VWpxl|0!6jc ztTxg@l-#Y_DA~rQ?imNuDydEg8upE_JYq#52jUsvJVs&al=qM-sNvUBUpI0x^pizL ztUKl8^xO5kbW^0<4Or~BM#MtRRfGs2X7hOk&9(EujR@OGI_ln!gJ(GxqN+}=vLR)**a$Nh_gr`gp6%R^^F z@}<8bj(TYm3>vxZcv1!lrl1|`Pbqe#lf^k~S^Z+AXnnW$xL!=Ib!lK9v+!E8zs!IhyV7J6j=vdKUVF;VXp5&?sCiwK@u;T<|`r^li|8vY@F8`1-w(8a?L zjj%kijui@uLPj#`wKVI))X{Or^(!#kghN_S<`NBCDD(#CHBcRGpUPYMmv(W?wPrCv zbfcu7!qXx~20&B^7eBNgOC28%0^_P6k;7z)%dH-+-|yNPT<0j$&(Vc*x_7xX95>Z3 zDo6xa$ZaPnY(bR@mJF&v$S<)77xZ`S(2LKc*5^9R9g5w3?SWRpLFfrZEPYd|4WG|= z8t9Og^LPQm^s@BdMM@uvKPDHMW;d5jS*GIdBPY_b46t({{tIkJ&!m?K_5lO3mI9;` zyS6+29clXRFzCee-l9fh>K zkGl`klvGHa%bSi<2_1VQ_SYg3kGw-ou11wu$X@q!WSYfD&iS*QCOwC|aZw+?_$WmT zWj)yRe*Sb!_Jhwn+XMeE9@ zk6+ZR%s#R8Yg7HFjjrBBJdeLlRAI_lzhIrrgfL6!e%? znD2KLYL7+4xmOVMcriF(3msnNjk zY~V_^Mwo{-*~2=YPr%ND$qnn*@1kj<@+Kp(nN&Up2}-9-E@cMz2ugkk8r~!0fT|@eQg?I698;IS$F@-WXqo_Bt#`3sOq@6Z{KNvZI&sD)vLGllQ6IE zET9USyz#JGa4tHc9m4=inXw%iMUh~5C))Tz@iBMQ>@%PRB9}yP99VVn9te_C*>o*m+F_4}Y{(kysN2LPC=K;ZSP;fHlZ2_XoK);cXqnfyTj|&)A=i@3^<> z3Ph=6{_-ukl05OnpONH0*v5Y`2?>Lrw*H<8)7jpIlS+Z^Tmw{mJ&VDoFiwM9kkEjFrt{0qoA zUxc*@DPQmXAUX>BJ*!iQLC-+uAHz{Owb6h0YrNDS3=6OcT=%D$>d={@=8#Y*iF;E` zHgv1e~aHh>SLkNQ^`nTTRo_wJ%6ASjqy+I#x4s1UTa;r7Wm%} z|NTB0^33i2J>2!gXfl6iC;vtm{&CU%KA8M>v?tF0tV)>z}_t_q@bT6tzdmU~$E7NxtObw=Jm+WIhTbb}Xz*JyQ@ zJQ>)jIX*><4B$<-o+Ew2=pYfe;hs!Mmx6vov{-ZfYd+O9&H0gU&3rPT3b*de#q^G_ zkroax!aQjMvqsU*@V+8q?ktUrJ!CH7yKLD?(6?j;4yj7um?@FR7Xg%!s>tKdb^8HG zM(IP^HM2;5qod-uocqS7`~F#dNS=|EtcV{tLj5q_UM5Iu$Q0VY5q$~blXx32<#v(Y z4mCD1^;VUi$4o`IGHzR+Walf_r}KAjVdqPVyG?26Z4T(C(<4Xl$>1_|^!9Ad86kIBAX)k&35Uqj{LgR_Y)UD!$wyHum=E~F_NT~Vhkh+t4N#=Dw&KGm z@6$ArQDswB%}Vt^XCCs=a*hFy9pEU((MGB(N|4w*i;ES*HT-PLAa*PE@Zk(Wr%lA& z;4Bqp&CGlO%50pcuMvJ;utY~=fT<|v<==)^nOWZ}dP^N-B0crp}2*;UR66U~84WALxu zR0>DATrnTLdAoj`jJ3CIm6BN$J4HmmJ2~m=nIdG`GLlC4eN9pLexS@WS1Z{WP|9fb zt3gFjdr|$ad9t1cX#3sAhG)4H~n$a@9y=!FGeqwpBUk|(sQ#x7Y>c@ngEudY3$16?ufPN{c3ug@#a;$_Pn zh+$jb=Er9%6R;kz7nv%XV{70?P(x&SG7h=H6Ph^V zb4D6GDex8^!Tfq)@hI+VJ!~Ewa`s#mGhxiU=vV2ulG0!+vTrkeWrryHxeJkkL7NCA zr5)V-XYmfn*h4EKAEE{1s4h*}nf&82sygL6NNe1D9z&`A!_A~FO~N!}pv+mee$lq(hbnkuMy<5R z+XwnwWWA&@c_I)?^HmBRS4^<*p^Eh6b{20ZOa}O6OK{-fu-ONn@v9XRq8Y2VQgV%q zCKrl64c)KqrJ_#Ej3^cvk#Y%N+dyNIgi54Z#Wd`nY}uG|IPd$+pq!xbVsrK}+j&1; z&|)rrxz8~2r51^C8hGQJI$2U)ufZ+53hW5kGGf+1CD4RwNLD(}8vt&xOi2h+Byijm zTWF|b-R;}xgKI}TsTZ!sleA}hK(Re0F%cv5=EOoco<^Sf^)mHxjEw>4r>>n2(nrU< z;%?_bbM_F8(U8&pX%y+3gegAj2XYf#!gXl5uNXB8`1Ps^)R)tmUs-G~G+x7)Ro3M0 zW~b~6D)*Rw8De)yo#E;3G*I4|Yl^&S&Go(P)jK{3(?LrDd$88(I?2W*pIu%~>k#6= zpB>Uo`^Hy6hw(wLrLlcOx;u=x!rI&+s%itQM zKMW<>gIM%oFqrhdz!BO^Ea~<92Fzk-bP#B)7CNpWR}>Mf2?n|kVE!!8LSW>rjk&Jw zSLebWv2wf!IAtrhnXZhnPR+{D_;r}1_C~^w25G1wT2slml;0!rP_ZQgv%NEP0=KjT z-NgpkjZ>RM7Ce2cr_V(rY=L_dc}`qPuxT4&CdK4Y64xcG zz1c1x*UwVZ9D@DUJXzA;vIrsX>icDCnU%M8DvDYS(J4e6bDoZyx4p1Ipe>fPGss)k zDyDXFGt*aKfb2uj(1(05IP#-LpJ>~faPS=I;2Je*=X|00lS4mPpBg_yAqX~#lVn%@ z>b(sxO75hr$L#tkY&Kqbe`*aB)Vf!PQZGKXolMzh2>3~to!CTxVx!cnalMG>2{YN2 zePI2-bR+o~K=g_&!P7qs0?#vlp+F}L$d}Lx$<=UK#kIn(isGRoiqqL1%4S77!QdobFZs*zwu?T^rs8-yq;&dMS8o zcC6ps7dJB;L63&ze4y1)4i z^|)9g{^M|>rVu@-<#~-BQ+#GbWlTbFhxWYUYm?64ag1uc0{~r3RfTac=IpLbb1dT+{6y8p1L^GQKf}fr5Taf~07uPc;NI6rcD@nvh2m zNoX;Z{+JjFR8EXFGL(YyM;;8|QyH~_f`lLvo;lnxYtqyC58gm0_UF<%U-&+&=PDSq zDY(ibzWdbu5%+4Qy7yd%N>ozZ3)e1Mc<}wSJfU*DE_Dh0AeB%bCPpinS!4-m>s)&* z>|UtFBRa=7e%WmAal&4)Tx9D{^!(Q0vrOd}??w)njgwx+dvn1WT$yLKkBVp6WvVo8 zOJ^^ummjE5*2se$28G~p<>@qRQrS-Py{BW0;PlJYdN)d8eXYl3v2(#LO~aZv&&km$ zu@kY=-`1je3wyDY^hNQscD9F|n!;yoS+FRCNhKO1phLZH?ekjk^+3+`g5?&b94i0$ zArsCrKI7w^UfrX=$)d=)ozn!PCNATZEP7ekDJVMbk4h;0heo)=aeSNax#-jzP1!Jzjl z`e2BQp0nTACO#c7Te>v^vJq1(Fv7i>wQ)|g@!8|JP&Wuu`E@{|QPiM`=bAzjV23MlcbaipdA(Tc_q><3S1J*vs zEF?CYp^SNClOaLMXW$E}`|bt}Hn~Zy8>?<_{w}?U8LcqSYX+^Z2OR|v{aP`Y5kXm%v7Ayb6Fte z2u@Zh<(SEvb=dMem|)nF$g z!SV6c_s7KH{^}6sCjN9Z43|d0Gg|$Y%7{I=j^?|!0uPL0E#n_VKw}T=_lu;E!OV%7)ay^I~tEKJc zEXJcY$Otnp)1d(nMvPNBA}X1hsmwAVRj}o|M!N?=P^pIJ?ucfbIq@kahqzz&BO%g5VD@x$WA@EV!<2VZY}Lleg#6wm%LqLFe=o%yI1(WAK%;f>;aTGdS7kF6yK6|_mnLQGsoqVSa9@w?NX zgq!=mgRRv0g>82aZo;wKYJ2RR_i5a`nsc~e^wPA|rGkX9l4*21!Mca-5Q&3Kp0nVtM# z#bx5g&Q={%5E)bVk~6yUPd_~NrEj-mN5BSKsc_BjvJjx3&V)!HiD3!-Ui|~5qwe|J z>YNjmz)BzN`c=q1^NEH8ti6x}LP*AZNHouf5od9wvKZOf9{wJr_=`%a5+>#VWn(R* zt$u?&YAglO=8Jyvr<$o{!gSi)sbz&W(Z3n`QUvy<dkh?tg&%jbG>?{Jht_}d z2EVW=Wz`7)spkfzc2C0C-EM*&9qMwqAY<_Ss=o{oNqHq;x-n{qqETPXv$wEoGpHJC z_qVNIwQFDsoN_3g1hRE42B(^A9{OX{+<0p&G)Iz92;<0`$801(gay4_y7k9xotpC| zH=dpMI%5`U<2JIvkTi;MX32dA^G3s!hVmv{d$q+&Yh(VCYM~AhbR!jHoXp@S@WI0301fc z2lnMA3w<%-2PX8XRfJKBFZ2pI9?SfeN;;o(DWFBi%NHqS-(Y5NQEid(#2Rd1lt!`Z zh)tdWVc>B4b@tojna-biyi$xQPw=nYs+V}9E)l1Q~3J!(XS>@cVZ3|I+MQyIdK5i=Me7*Xs zDeB;TkIE@vd~#nd1qfc51jm@PLrI5;b8hB$*4ik;p4Fn~ z2hARcgf9*3Kh)d3%R9l2fU&5eWl1VWu+wGH-3Oe3Owc^Q^vGeA`W-&h3SdZUAv z=*Qc%Og^cdbDWt7J#e*nrlRU;Qy=_Azei#)iwjYbPy6UnQq5IPiiyP;X7+Lmadbm^ zBd;$A=iw7NH@;gsSjF;ymtYC1Iq$6r_2XHVu* zQ7N?l)+U$Ri`71Oht{WcJXphT4YzCK z5*x^ic3oshN*#14%q0Ix;B~LF|B#JFIZ4pR2y^#5?#%*0p3_ zfNQ26cK8NnYI_Q2D%S!aO>EbX{-F7a(HBW-l0OBvCEQxnb^cFIT2O{Fe|e)51|PC) z2gzmzper_qI&YvgL)wu(iDbKwv3o#kPGhKTn<6b4Gah1W|DFX%SkjIDmns&0&)Ti? zPzPDiGnrAX2fT7avRn;@qL%QkfzNuCoD46v6^W>pB#l+IkuVU#bCcbu37T}S0*src z+LFI^X9D9UXuLmoU+9Iy4ZhpsdQNvFaaqM+OxtGf#rw*ibGKVjRqP-RTqq$2sE`?sD)pLLm3IFUOdFq5;ZD|ZM$pnK^+-+}_b=Vm&;v$bMRz1}@FWL$;V^N{oP7!kLVx*_(ID-_?whn!AM?i9gCy&bNmbaE%#rR0px%jjpZ&?6)jW3>ZQym$2c$0eJ* z&v+V$;x%|2RXs>TL!Q&EYsclM*E;-Th>r+$-q<36pwM(<+UTU32b(&z%g*!XYQWMf zX}WO`P(bu@uok5KqGJ=GSX!Oav>ReQ5KV-q)hlGf!6qYj-2o8ChLZk}xGzLc>SX2$ zre0YJ!Z37P??T8BXFvT3RXWM~RLPJWW3ICelWZa(W^bY=hzx-aOfyQtnUcEz*yKms z-h5%)TL_u_fAv`z#p(al`{e}d@|+n>zq&jQRl(}OPsBh0;~(w79ei4pB=eLX>XJGe zyt2#R``Fc>Wl~q67@er*x)IMxh3o$^Z#46@`uc^h2lj;w%Z=%9b!lxYRotrmOL*@#pgk*3q z(M~VP)pC7wJckn9*~WjC^pzE+d;C2SEyg}`71`j&XUozqQZdtumVZNDq3oiI1Ix?# zeU@Ank7)IWnb2WGtdvMRdZ}q94|3JOUqGs;bFy{$M=@*H@sW!sx0RQW4TwifBceZ1 zqZ{F0lE~0r-p6K_@cTn7$mshdGAr5=!E>v==&R*{c99$+4w|S?vNNa z+;5T8$MNdB+33jJlj879!R-~t#j)BCiOc3CGAAQJu;kE`^T**pM9fERP2+?dfgi{w zsunyM91r;#Y+$nL1KsNo^yNTn2EAWN&We8My@Lh$n~0{xhD&O4__>2RIYTD%on!!> zkpX&@{?cDf18>8+k&lJ;W<(*1!jfkESVp-xb<*~tD1uCSJGh2asHkglaD)o$73!}( z&UBPXv4r0hiAifBFZCg*x-%?P3}PNBXaGg`3wxm&7l&?Mn4DpfjR9i>mD`&~bF@0T z5#6M4?@p>t9N#V@c7VkL+!>J6rRH(O%b(t(_DziHj*eJocFp?HY}kUQZ4{u4nCH%4 zd99U@^a{;l@*>$9;M}c!FgvLZIZ6?xbUDfVT4eDPkIRCtH-b~%Qm#)+XMl=QzmCWI z`z;eOpV#AmZ@H9I(X&@YK^owzefflBLjBq_uf-AS>wI_h>yc{A`Vgd=v^`mOkok9Y z*Kx{WO_)el({p`mlEY0(`}l9;&q(oK?hdogV{G4*ZZyVTbUq}*=6ZjMS(KuHL7%eg zo2)aFi^vh@0J27i-Jg*!8~^veYF>mf66$&*nHvHzja2wo{?z7bXeDe=&ug{7teKlhejO1vbM(k`~?#0N-LoBjL?_s)$0dvytS)tWtilZE^dh zih;0Hs>K1xONwA;cnXN9_mC3n6UD=bKAdmXu_{@D_2K}R? zpFZISxH&E>alkaiZv}lC?7%_)qh>|j5=DGiQId>iu5#0yz9!yWS06)=wI2?Qis#CZPNqcu!;oyrGjEQs zgp}D=`z)1z>0C15auvNSaLYH)@owVzLW?E6_U!Iv#?m?eUCHB$xy~&Y_QcKjIz&Xt z7K+eParPsyPYt)y8nSb(*^Xijc}Ty5Sg|v1uG9N&I zEv?WWPqB{&u2SO84h|#yXChwZ(DC6cQrV(m3jad|Es6XouCCnTSO~osc1lz>?Wja% zsnGjE;WMn=iMp&oYfj4SdJ0u(#Pu@0GEkyE;ZJfB?ppzq1tKAMfKR`rr`%;dZNJYw z*mqFA|BvG7s@$*bHSf-sHbZS`Xoq~kZJp-L>0k!5B>h3Tr87rYF7J@db)VypA~EH+ z)RFSeMhid@O?JIkrW}rQ%9GBzlP@;iEl65y-dO^~_3-ps7YmODV z5Lojc<+5jF3cyHK5O(KVrfzt2kY+%dcBn@{FKN=zFdbZOtnt!YsMD@^eQ zas+a?)^f}WI*-f5t;%mqk8(>wsyB``HIn_Ir9JjS+LX0saq7%EUnuH>VRpMLq&h! zpj}YmESPI;QSb0xKdmCz{MXVmUx@=dSAqdrwu_h`v0*}ap$dV`cg@O9u2m_Zua-{f zqUW4Go|MBZZJ;w*#y@+0^kEvIzyKb8-0y?Pqr31Zmh_yESocwne~H-qCe=cknx#_+T8rN z`moAEg^W~%)s|>ssxsQHdpS6S4~D!A*%B{Jq>An{$rr%HAlb=D;&+H^ui+X>x5C2; zbe6s!LzWw&ybDoI^t#{4sjrffVxIPQq;9kU@I@T|wj?vhY-s22RphmQ2+IL6FQD|? z_8oy0`dndQw2Uv9_+{ER1Q`I(cxJ;8Q@flykq2!%cQc7n9v-A;g^7nzPaFD5W1!jQ zw>R`{c)70f*1ntSf%OQcCWtu_9;Fi4CmXX6*Qk1HL-27#&eUnj2Pl~vwPZa%#c_GDgdsW4PFF!3Ng#V z%E|Ri5Gj%-b^?}Ns1uU8NecI6R`@x!2REk#TbG}QI0W`ByME(`GOsKMH8rM@Qu=*R zE*>V`>0LGJb)9}75US68h;J}Jzt3)$*_3i4SZtlG1p9E^Bxw&E_8iasc>CsgfU+SN zoR5mz4#cLG=>d%X6lV|VzJa_jDHkwu?$90x_5q7nswG7u1~eo1l>WOA=IiVs77bY* zf+W0-U{Wb6V(EH^%N}kH&icW}fObYSPE!1Puq9io2 zeA5mIj5SiHK>ZjaZLx`SIsl7-~8m-;H2%2kFbY#iV$;J>j zTjrJQM4~-W$hM~R!~fJ&eLn|lQ<)S%WSLkyhxuPx)W zI_UZeQw}zqyYzP0RN8Q7!I>*NG(syzS<*w?-I65$gZ1CfjEv^E>cHWp?_1_xxe(xQ znQ0ihzjKYbh4os{fPEIS=G+qlxd90hD@F!pk?_3O2Bvc=|mb`#R{Tq4Ct!qWoVqFW^%f03p3VJM-`<5J?S z^vE0xO*L&yxUl^O2Lcj~+d^H+?pTIA=6yxEV@BIAh+~u*4}1MHoFXU>y=iKP@W7l)DbG?16S>>y-FpoJ~2ZH zQLY+w9i{*!G`bz}9KXhJyJ#r}B#h9P=_NJ%yt%;OcDGN0u8C$$=owJNR3{Katwn?} zy~LdOQC{UUMwj)a(>?V!Q*85k9$5K#-ekL?M#4Ez>O;SG=yuOqam`&V{N>TPkK20e z`NoE)1>s;FXII2NsUn<-V-;qa+X|bRe#hAF=@s>P-9{E{2U9x87njBQq2IAJ$_VYy z^~pcir}K6DAil81dqYY^ZMK&KI3h&x<%$j|ItTKO26RVX?S9owT3f)|1;bE8gA&nB zNVRFBbCY;emnWIrd&=w^$`n;)Z8g?~GdmvXP0t+XVe%FUElkT7u)iNd_M@Z16+Q{e za%hwni}zDSqbA4V=<)q%(=8 z-NVF^PL}?xH1cI-cu6d~ZctkQ2zEJBtX--ts#_=m1_SE9~S{qFP>!$RgqCJ&HyLyK3^u1iv>UWq}|Fad>!9 zt1zC;C{ituH^@^oOGehzJ<6u`H*y=4T8}(2= zT(~g?GvRs-fzDkW-WYhnpb50%V>l4~TL|}I`^x?aQ9|hW`99)ELx5hSy=Yj?4 zX8mQGCD)NvttOSRkwp=**gk10|2jn@eFv`Dh?`ri+=#JldM2*iJqA

%;miTg`cTKpf`$ri*!Pp6=PET@qiLS%6DR|&LO{c6E?LQDZI*=I>b)(O?VVH+`T zoFHcLTK-52H~d1|VYy*0MeUU+3Ou=IvgT^I$SeYG zH5k-Kt|Ii?$1x%IpC*M+y7V9#|I|^qp?DLC#EwKLW>~-c{q9{X7{GH@ZEbxnAOT#L z#iv^%%?qB7)^y$z`l3WJ9uJsdD83XX%uuxd=`y*>P}S$%tnr*<2n7Bpz>)9-A3yAJP>zrq|1-hg=MRi`5Q#B z-o+JnB-cFL|L@!Re+!1Gni%y1Nz|(`G`wu4W8Hf3f&=m|+%sH_^^?}wn&C>xWuaX5 z+Y6UEER)h@rSbG%0$C7WLz?!>V-xgxpf)SgZlFgeajkfs(6( zc7R7Sz}5r9FGiRIxLCim!9EB`qz(<~c#d2_j6;r!(G1%upq+$|kOaY{GQpS3OZQ-w z&nND>5;Eq(D@IMJfJ97c#sQUytflOgAial>LC&*%-uJ%i#$;>+OIg==B>~~u?hK|9 z6k{~n0TxYZW4>(41Vm8tO(;UI!@rh8IyMi4P5080C2TeJo3xqybQJq6;d<6-)F8ip znr6fFk*$HdOk}t2+$1P~-`h3y&L3R%ET@l!7P*bo%?`u+#ZVp@p8t3yNB!ouNE^78 z#JIa^MTL8x;kxWO1dR;|k-!44#GF#%)`#zqzL}2=U2o1BRG>?ASu?#Eu^blaE3;ZX zaoPYIoDKz>!@s4-=ZhKU1{qgDQ0@#J;B!Zk43pYotfZ=wgMZa4j+u}+8S&gymWC*L z;JF98+Nd3-Ooc*=MBuzM!OzpZ;a=$^E~g{h+n|Vj=yGW;^OM zo-&Q_P)%L_BHqSaZkGKf_#67Mr)0N^4ooJ8*S5%c(!dTN)*&r1(JGg0YdFD@^2bAB zD=dz$SuGTM053+?2iilDwJg$XG;<3XYHqYNVg{w;s2O}l>@~W@g$5nh0J{t}-JmU> zKn~8wddBcB)5>;*K-yE7_(iZL;B`=1aZ+1$_LP z7LU^u-A%vaMgKx&Jh0AEa$gglO}1~3SF*_X@#9L9DgMLx(S-4NS$OPx;#$<7gVEYQ zzd=)hb4_dx(43=_L^1Q5@dB+pafeb5ESJvbkdN-tw*vA~?lvNe^Y9IcaS&gIq2ZAF zo`1rnOUp%{g|NIyel51_3?nUQ29>tU(0<;DgjiT0>%^#}MYnQ4$<_nuy}nL3Ux8+| z*@oP7fFr$%6a8br-9S`CWNZu1Po+E6aBmI!q@NL<2QB4S3}ic9odk+dI7_G%VXVXy z!IE^{cx1We;yvBKI??jMhSZYwkh*qM9FvmAUEyBt`8D8!~x zd8|~Cy9QJcSZU|bbR-kobs3!sk@w*TROKY*_uHDe(v&jULZ;_afX2N;Msh{75SpNP zg~mH02CI}n+1g$LD|1s?7yqRlRp5?+AaB1Z-zuZ*oju$DGyh$#`B>!-gmB;zAo+}I z)kPaMyX|c450gOBr9`CYrf={xUAD!X@j*J>B(VC1W_*y>~}?M=+tyo20rlC;fiG&i4mVb&_+s zPwi2NQfsg-YLaG3X%3J*fWFAaM3p$gH-W)Z;~YgQT)r$K{#RfO=7u?SWv-k+pFpGo zwN6Hkvo60R=;P*_q;3eW>bb)rOWukoje(B|3%F{>vF7QN*uxXg3%zfhFBfA!8_1t- zvbwKZ*MpM16}ZfTPI?jHqV1);-h94q%L{vil(#0wuHCY)B>SQY)^&2VSFNFoL67de`}?Z^f2Q4VMkh?l_DN zls~To-N=YRh26*^-o!mAB>~J+3+(DDJrhn$r*e|l5}MnxDQmM7T zTWTfF)Yf>A4O9~hA8`y+h_r#n^U8uZ@D)zqcx9OA zqO6!pLO3XkGm`)cAp88|EceqX@Lb@BkfjNI=S1*|V<|b&H<2w%D={BQS48O5z3&bw zI8Bpw?0)tOO^jA8VUP~!8CPb`>yz}?H%ljh#j=d5QP%r->`S;;pQyxRQ^RAo%NFfIMK+bBnU8 z+;%Dl|0U4>5~G`9uQ(h#e=&Ai^>eG;2g`Q7UHC2239wbz4qe%ug3%Kpy|KAuOqZqj!1o6AOoK4#i29rpw znP48zj~U3OeBL{lifbMMjpM&(e#qoH37AX1|A?cEMr}wWt(_wonPnj++GXp^Xd0B0<;^vtT zgB^gI3=@qwj(y2I$AMJ7!(f`gQ3zeY7?cihEJ`Oh4y7|3hvNDF%Z#Cx3Hugl=$GJS zwSgN1qxxYiW=lNi`gJIW0XZzT!@UMI-6);sMp%RT`>a|UAZJB$L*cp3*%Bg42Isuo z=LrSs4*iq*eFP+DcRyhQeTR;t3-K;m6!^nR%_X`Blr1uo4#%>l)*?$@+m3BRcklQw zH;bY`#qma|^^pF=`^OC;@9JU*4?zRK{<@9`9Cw_(GpJW;eOP-}uC75qT<=Njva$ErPG13E!mcmflYy+x<-91oh-5-vRmxrc(bF8wF|Ja@I|&M+K#n3sHeuh8b&EqR6l znlHvPm}+dFXmft*X=5mSA5&$9i*5oJi{JG3LgfwoH+laF@Gd~k#M$BZTo7GH@Au%@ zBn=iFZsWpfCq-wo7`SD3Uk-Jii29ca@6a`-?_)*uxwY1rb;}>Ks&dFTRRtUh-@7zR zx(Ui_dC5_FbQm~tH7idwr6l?vUTXNE?jhOM(e{B)KH6*lg+W;{`5DSD0YplSS6XX- z8+I3H%)7n&YQSf+G~UQ4Z9$NFGQ5SY1&NgLS29h6?7#wFa9?#%4SwWRhAIYCnIYf$M5!0&k8PN66%T~$Fr`ET+%3Ih-V zbSxBE^$QfbSwIVJE)gBe_u$0ht%oAY;U69g$U?#}=_hI=06;=4SO6%f5MTs?X)7Tr zJnD^TA$;-JnpkYFZIR-{c3yt4?-$!36dhe1@QKX{$#Np0u>`2G7P-m-Z|IMnxYp5s zY4k8~x}~J@7)d=-_o0ppO$J5dR`1Z-n__QRKMRSdCZleO_Tq=6mqetby?jq#0*@8;<f4rLukTBn>h*eA3pRzEYWCfz9@Qj=WzFzXrR8vsh0 z=b610QU&ct^tT;yfNX5}wf=;e4zNG>t8`jQdL*!AZkTP&%EIGBfsyVENB1jmJo^ZE zH5z$WkY~T&-PeaNhuXMjaQVOY@nKg6{^yqu@fVzB@+Vi0lcM@7Oy7Md7Q?KSH_vr& z0LgfQPVr3h=v;+zcof5Z^F_y9*-Kmo>%w7Y>2b|I3`5do4w19JGEiaXK_oF|P;Ee=b{M?Q!I58L9k>$U{PZkqxtq>AR8 zVcI2+R2hs{7ls|JJbzW;!v>>}Xd9rlEb=Ug`TG{$q(MIO);$p?*P~+lkLlQ$`MH3? zGYABNhjYN@$6It4J>(wkZL2-;=E?rj!()~h_1S5OhTu30}1U-l9Jc>K+Rb_7 z@CLDEgWi)@>3*g;JlYP?msliBUt4b?!VJU*RU?XlqCi{Y*=^M#JtN6`hhNvw?QAdX z6mD0(i9qDT219ZE^@m_UoZ9O#NMW0-o>O=7vHt@-9fCh`=n|gr8cg<>-o;-)-Y`Fy zgQ_Qz4DM7K=lYludT$d~-ow2Y1{BPlF}BW9t@HqG*0)yj`4r}0W8b}Y)Qqq16*~zk zt$q)$@1m1N!Uqo=R@RY~QCJ_`q@}7MiPs=D#z=%2w51)nIQWShWWqL1Dx;b%+F?km zzA6>Tw0K@g=@C;MMZiskfWGx$yCenW=ynw&_I{zyXv<1WbNcj1Hj_toXOwd#qln(_ za>wD`jd)DEGt$1<4#mxj7{qP48cF4U|>==dzzYqy9uuP*lEWN|{N z_h=V1qDfvAfN^7WqXG0|tQkYQ8wBwpDG5qa6Gx5J#;#xlF@D&$al8$%a#n?f_Cyv6 zlz0PKPL;T8q@Cpuvnt+#cT<2`=k3&I42y5Sb3RRHb4x8Mx5}oVC~7CFIm?Zh5J*0? z#G`9g8m(c0CT4bat#N+8c4U~ZHE#xsKxOi|vEY5*4H-N#>r5{E058GVrCl~seF3CI z4V3Dyxkmse=m*sD&&$H*u>XNGzpprB@ zZO=c_%w(aSWDYG1pL$zAn$fMi zO|1fD8N?#k)xcgI{v4w>1H*kSSj8wCL;_%n19Gac>O7UFw$wp#l{7~yhrjnb4AaSp z=#TqFc{?ZVEZ9`EUSL6iTR=LGO1b{_&!snMLz(j zvndP&46B)WJQU86gbT`PQ5#d$r_QHxU zS5R}}!XAac_Y{IeP?}s<6a?EAn6zziv(%xSCBQ&P_{q=4(~f8GF`6^zZtuFcKWB^K z8DBc&oQCx}5}^(O(w`F97S5`1#{j3=UUIBoWi{*)=WAz>1#)Dx#>s>j*l`uTLJa^} zyg0q_7=e)j3^*OQCGC1t39qj4z}bBE3t489Qqu3Me#bFXgKaP1sV3=~6Hkd}wTX;k zd&opFUNecWbS6_J3Eh2+SM8ZsfNne=8MdKHc1PeVqNq-A@nAdV((*_C^|u?abqVUH zr^U%nX##P0@04~-&Q<_mpSIvmJw;B|4*ldG6|Q}WQHw%ORZtNahNLnEKaF-B3r{rW z`g&&gLzT;yCvV?sr;-gce~=#=wn2~THYrD6aR7nZv4o_EF=O_{^=v*i3L>HPq<8HX z#}vx+-v>s3>h6|Wv;3nC3T3xeJHLH|mO18Z_KCtneJ+qQS!s&1SzU``h#?KJk1NNO?D+2*a8Lz#QJ= zwt(I(WKfbWC&E-I6N3QRcSORkV=~v5&>&0=KXBMc)^+- z7^CadskgWvEDA75dAQIwAg9OE&Dc3w%z8JSD4$qJKwOtA;EtenbYz(JN-$^OzFd#j zgq~wKyxSa!kn>)7gMtPtAcW+ow3LtuEH3!%1yek|`20|--Vf255h0*lswC{-_Szdl zCWxlE4*KsKg0e1qS@)9}#=GUxd|QDXi=z7d!7Un`N5ik9m!ZH#63G*Bzqe+{ zwY_(!XIxFqj?W8Bg(^K)NX??Tc_y|#EZ)+n$SPm{yyO=}uonZgwt*tuX2L?S*~w z*-JoM0oNw3ks5(hgZxBBsG2Q&FFde;NuK8Bmj)qHM3gEbJvAsU9h)>i#nc(QSYbVy zL}PD27QfMa)REJnBGtGkLkh#X9Jo)9CFKLHBy}BR;c1@m=`bjFB|Q3*9yQYMZLUYC zLIH14X!R#YT@u{@7IS1NkAe$0O*3V^ct_AciP$G3w0Zu5onqy;iroD?!cMaaT1V}D zAI)h4@(s#Knd~>VhS1I@O~gXX5SZj+^2u~pOF@=@t7V6H=#}`qebw_zP{8;UE2?CM zEg*CinS;x9>3R`BSTA1+VdM2Om!=eeHwh_*;K{1}^Mvoq&B5D{9?1EXCaVJAAs8bE z2*l9&1a_r)q9Ot|J2CD$;hiA{-00>={``-b;2MWGq|ezX{*>VZnCu0I*4WH$0ILKr zQ|Z5n2JHKw$E^Mgc2fD46HiDLF*x$As&fo;xe*ZZ4CK5;5&qZZ%Fs2N0RZ51XXu2; z>zn!4Ytq9d?u4kkp}=o%UTN_Cyi%G|5Qle@H%MtX!(8CXX%dmOrPoF<*@@_huyXfj zQIwc;%Q@%rH>kJb7}(1OeT2{_#XSq zsB_qQ`jR+evy_iI8zr}k4yR4d>FfM-(?3xB^wI1_y4tVo$x;7km$#v5m9vlLmc~00 z3;8VSQ8v9Xkm$l=m#~HxRFzpirSk{%+cQE&f4}dv(=LoA9^zN~=xUi@FjY6k5W9v;+W*mXrEd*u^f)jLHymfc;s8e+vVm|$(I1p?^eo}+V1nS4fU2wdm8%5ziT zCc{mFn*cWk{4WKaSWi+r4a6o8lMNsyn}2kcfT&D9G1)v~k~zdgGl=p3-O%(CqWvbQ z1rW&#S@8+)0q({z<@YA#kEqBd|3LUS#>_sNTOqR|rk?&9y}Ok2O==9tVkBrOO(uT* z4`!w%^WgloQX2T|0pA1WRlC__Df$ZQnXv>frcu zIeBKw>5ylqeEJ#I!)bs1feC%d9PIhXvJ8ZZo_VS|=T76H;A5W{aqjuSr0hgUB!DKx zFbxfPW!|gK@9We&^~_Kj4#jN-LKFdo$_O^7MkOqZ>te0cFKjdj4m^D!R?8 z!#bCN1j_{96wt331|=%KS4bAnB`zIWts5sRo@tAE46_qcb7Cyz+>z`X6n#1lSKMIwsqCN#|HXE#m;iVpIE zr+<7_JK7pd=%J3B@vob{r48rq5kPG%38CoA)OB`W0GLigy^h91DwX}tLcuQ(54BMk zEW9VkP0r7TrK9h>H>&`*gPbA&hP*Xr)i<1l88#?zICjuR!9p&PR`thP|1~dHsPW;B zoD2XKclS*i&nx!s>T|^;_vVu8Ed$(^48nsx9_vp%A{PA0mU>cFcoIK^(x^HAm26aL z*1r`nn_S+bs72v=9_9n z61l>`LxEX(!-F;qU+WX;*pQqj`y-jXrpXVlnr{in&e@d)wi|EMGCAitKaNl%E7NMQ zm2LSNVuc_x#pdx~Cb>Urpdi1x^uV+5gl^^NR&(i)X`FpITwD3LuA9Ks=nNhK+`Bi%vYEx&2UV3MowJazuI4=^2 zevd}tb{{lynQjtq7<-m910Q5AckCji7R{i_%9p z^VHG?*lF@G)-VAF$+IPPf$9w#2?Pe~F!c!~kxN6_iM9=BM*}C8IbfAp>9M#V+Z|9Y zKub+_B1WvU1x#aYNbo{7o}#fUh4n%H>ey^-yl!S5idPi5UNqGhh99?8cx%gQ1BSl$ zS#*o$hAF0xZT-8XCt`??ldwR7;veoOkGLyP$1+}}0)J|5HF7}3(yvq|1Qy-fxKZsb z$vTOaCQ5aWr5OFEGD2M}csINYR|ZVvr5O(J=eG$O(AwfXmoqV{ENz8XYQQxbYSuzr zBdKjz?0^cYl!Q!j{w~d@Obqk3&#@8Rg(|YImW3D=Nf|ruW;<1Dy`}4ycx3eC{8Z$i zs>7bjN|DQVqB7tsLRqT2E-${qfqRKbUc7-_O*otih#gWSTC2$FFb#0MQsj zAqG+R+FH$krGQh;7^kF&lSuPHa`3CN7Gbadpb_-&i2oWMt!_~n0>!cklmH8d?J4{fH=6vK zJfhF2JcVfZjNyOI*WHxNGIc_Gz4jb^r4W+hM-TnY3Zb_+E`jE;Kuz@HT9jk2o(Ep0 zgkqb$;EiCMqip4{Cd#KzhA^ZK@qWQ3$&O*+u|~ zb0idO=b0(yKh^s=g$y$|rrTfDZ&e(z#y+hNK_TNuqq$wauT3{U*if#RazM#^6OU=< zvH7>b|A|x+Tl@M;BLzsKLNZ?8xbpl0)yUQtq#e^=iD{zglx(as#lbDn;FK5)v%$pB zNm+Z!Nzt{F@?-!A*Fo`$hrxRhZ5M0|0*H}%aaNa^!Yy|$%5@!9?St~Ey84Joo{vLK zF=R(HeUa~LsmZ>e1N}Vr0EdhZiKARJlYMvtkNu;HjAjGnGmRoF$?lWje-6RW6cPcF zeTh922^5P^eq0Vd#vm57X6Y|w0WINz>+$LCh91EvFB!ZYcm1p{VG!9>~p62z51b~ z1u;Y`Jb}$}9TOf7Z0nQn%#1i6ePG#$0eZJCi7|Din%8vagNJ%q7^;h>od`@5cG)_} zRd)qMr6vp#1^M&EED`tVvhEh+Iln<%V2!@S<6f-BxuS^F1rj7US60(czDL6wy5oI4f74hYUHA zcD+KZzYb%HHA@W=FxOa@d~KMxwkX1u@zO3~p9S=Z)BC1fMt3b~-dW?VF~)9b?;BB1 zK_mjY!&d9#!zXTLJ~f@RAxQ*AH8!yzwkOH=&SJo~bT0B_do$~@9Cq?Gl z$R$g_!&a_Q=A^J=#6t$`^e9Vu$Ea)TWV_)ywWt`$xU+XE16~N>5xLQR=>Ln5T8sc( zl_6G6xnx3Ja9rwvy{{$YPexoh^)ME+V@bl_sYPWK6HIK0TTW({Tq)q<0S*ycYo`E{ zb1ugyqTd&DQcR$tQ)!NDCe$mHR=fA7SSuepTJC>@cqVzLcMO6Jsf8IZ&1TtYkp?l+ zzG6ur4Kb(>`mj-vL?4SY23h(JJN$%w#SkgAbPtW+t%`tQA82loHrJ~E1GGR(zcfuD z+}ajo@dV4Mf{IEe;ar_0Xr?@^Cab*A_q4d_T_~;p$BD3P=QF7EO@-n$choX8mV_-3 z4>luJf)mmJzs{;_EV9dN<6DA4kO{-=Sbvgx;9TDID3tg;j9P zAOHXW00PZFo_fNY`0w&nlLX$)h=}($b<)le6aj{TSft`k1p^er@QG#YU3yPb1WM^Z zK|AcQ7MZ6;7GEk^AzIO+G{eY~L%d1l7kIXwz-1S(3w1@ekF+aGH6n->xF&$FpOLev zvK-N!AL@sMd`1Vx<%Dx^f)HfnxIczGO zaImk#*h?t9S5B=^9)^sH&-oRljL8e|FF!|ylRuGvfpYhz%Vn8w|8$^+ae$<}k=O#{ z-J*M7d@f}lw*IFT?oEyvU8b&kBv=O)B zn_r>eUt0!-4`S86SP&egu8o+NIf_q~$fH<(WKB*t8Fx2c7DO20DOtIE;V5LTNFT6h z1#sn}K}BEedY=Fl)9CH3KdoQFo>KMN8es-z?Kfu?_H41-$TyP?AI8+8w@S5UZI{@h!8ZnOsB6;_7Reh{Y2iS+5>drv5+I9 z_B%BcsE~Oyu@HYlfpc~{${#XUnHSt^u{6%^_6^fN5zN0Z&%Xqqvaf?!9?{aoF-c;N zw_TNSi_kng!O=;q740w&(2eb5Zm#*1$tnysTvocChSxd5>n)BPPLy1?v95lm) z1w-?X_Tmuyw)>Nn4+qF@FFIl6vOL8)t?HcE^(p3&O5~D5M(nTE6UxmuTnxW40qzBN z3E=R9YLEl7XA(;@%|uj3AfK_QI$>&`!cpJ6?dVQ5K6NbHtrG|<35TP9{^zD1MdwL7 zxswZ9cpKZPEobg##eXLAmM(W{K}Ysb?9!VVN9Y0xTO+N65<1$#ptBr&X&g?I;-}F5 zJl-3Civ5<5H*&jb0m=vwtH#TBaV_dgMG<633bvc&eo2Hj*~Q?cIGTnGulUlnzP!Lu z)E_7PyRb3t(I*8O5w&<+GKMG^fcw(tioZ?kpAhmkTOTt&HwQ@barQ$3 zJrbfWErDDE-4)v7lsP&HyM(s!?KJ4^e6~({2#c?EcsKy2G_RwSI0~b24pwB143(*@ z&(h&SfCO#x-wa7-?MV)``k1r?@1UoOMdy=zU_g0?Tx2Xz+vu=9`$+L4$g=)s+S@TV zWGLJ&1AEA=j+dyea1q){d9aI(vAO~^u>qPrlorxZp8hZgr+zaWiZuupL;r$AUC1RR zre-`QAecgGAF6UEjY{X%ONf3^TxY**U-X5p``<3JUW_Q~D7!@K3smn@b_EY=b`l{A zMsXE6lM`_<$6sP&ejZvzndyueCB;|O#MGI?;iU8Y`&&E;<2L>D$^L z0Z`c{G9?fA!614SwUzgu<3_jM;~FeH6B9uzj*AmnjNBR1H}FOg>!%zeIZuqR+Qulv5e9fKPi{Hl`!`lhqIv50Q}b2g5ei`A%QB(}+h? z{=CrJ3@u2!S^0}b+E>6sn%3PRU`FtX!Fo>`Cbn6Pke`ydFlA!B38+S+O?xfng0;{F zD^IQ0!K3+#5izXlNpc0YyZ}HM|?Yh4X-3 ztAqvI^AshP_)G_FOrBYNTpRfP9dR+=|5cqM(kXsV#2XgnIeO2|c>?LTj&#J0@sqn^ zZmpsvj-d#-_Hi?}r-!s8Y!Cd#0QqpVw-fHiXss7|a5^9Z9s+kUY!9d5E+60 zrvgXO1m05_uI<2|cqY`FapPGlmRwYILpN}>i4A}tZ^zX9UH=@he5zWc)hT}qdqHxZ zjp|W;3@q0g#2sN{WG6EvJwW9+a}Et^F#P0kwuMm$`JH(arUDNmD)>OAG{{J@>Sk_Z zn?{En>oL`A2_#9r2D)Bl^COO9d@(ekZDkcJ@sHWYr9- z&+9{vhkc#HHPkZ>IStob!b%clNjl8(aKD2N1cU*s=^%eG$0cJVH8<4&000218h{^1IYQ9#DdQi0rz5Cl zl@XmxINEtCwR3)kjt(uIjC!QrDU8CMUjj(S-k>KCpsey_Cr>z?qswDw)PQ;d(TG>j;Rt&Q9{8#H+6K_`_$0N1Z@8>oC~Px0P3%+ z90QP^Te@+e|03vxr$kJ;E(r{bPkWQ`-v$oVR$Fnz>{RVKqd^!A?OE`B=#7Z?%&SdmBQXYg}1=lVaBdP$&1ZUs(>~REj<8?F${Ggu>(vz_G zdPow!g|e8QOm6jA)h9YZ_071$F34|;p#9U!p2a+5uZm~Z@z)je6~H-52e992WtUTXyg|7L)FliVV=Q_qZ;|#OthbUu2r9MN|_+ z6Q2q5%!g+B1$X817_Obt8s9V&c;>i86a@b|)k9A&{;be>Jv6!sw3Ig44a>6xeZLl+ zcT;y|!ul4K&p$=BQl%XYggFPd#;f_p8Z$G?JM&Jnh)S+}^@2N6Be#kwnu{B8EyB>O zS;E%jJ`^J=xWEUj09}T*Wps&d{GzFX*POsKwD0D&T&=Q5@=ySSLjY+K0>5PkDRgCr z*uw1qNNbc<$irYU40@0i<$>pvMS^7yyu1t*bie>IJL96q<&(>fDc4IXj`tlzP=oCD z&7K;$G%Dj-kujNPm*PbaqK0g8H_45z=bR?}D=QMkkct25u$@)D_`3A(!-OC4#$`33 zb-W+=@S#nn@W;r$S7;i!dsN9Du^UF4ynjmZj}6HrTx_S8mLtQKY3+0VVhd~Mcn_Z< z*Q&_*Og#@>ZhNq>pkO9v+uKfKYWb!n47i#~p#D;&G`+=8m^!fQUQQ-|P%>v~aJXws zoeRYV0*JhfEl#kO|M|%j^P8uI_RZGhUFja8H7Qvei;hbev~OaWhf=s=u%u{bj?7BO zJ!viCG@`EN+~k(>ly2S*zVOMN!u47@ZPS&N3OSF^yYL{DU8r-evP%nuwsGtr!6;>l{$ z{tO#}ScZ%{$nGny-#0v{6HvofV_E=nnzTbef_k7?eMPwO0PxG_bR+Es+L&g(|Y=K zEGMoT_69-ao04|Ub;9_~aW2wjFa)i~_ek9~-Gt#vxGg(c<;RdZKjY{RY8{wi9Z;0* zvtoV?W+#tb^pWP295e(}^Sng9>Kq#zhe=VzgSGP7BNk%5?;F*IBo|OWqB7af0nS-B zY?%HfNqE80q^!evP1>~0Bk#t}tZsn-kei1d znmcbcNpWjp&JTa20veDMUzHN`NJ*!Y#lJkG9nw^Kxh z+-Eo(SBFi#wIPbEAz-3@)C@jSRq!Z`^$CY{-E5h)ZM4}3 zn9hA;5@Gf3@dR8m%(93f5Mw0PvkpejNf0>3yzPTh!@0CVP>8=$%t9r6vMU^z_GfJ! znv!BIyfKWDku{0m>m>9$U723ynE#Nyc?^>%2k)}YBStAi@Dldiv(68}GDTz)T$ zU^%W?XwTLKCc|Zv8J0`3_jKxNA?IL z2#Jnqfrm#lYJA$+QClYHM3sz6&*!C(0m3cTU6(P@>y1uiM3^J(^EKt@EdL|){PJz-svd;m`<&TkAP&tY$T~fRu z8{r(KO1mx!v0q*GE|X)r&6zTs(_FHljp7Nm&Sy9G|3`9DdH^|I>K>5~@KHy3wseHl zz^R8_-mTC)s5X=V~&#%(gXg0#^ z`%g$|3WxBP#)*FhBLATpqE*dObWCoUe9T!^*0unjCS7peNRy}IPyhe`00BNX)O?=* zLj=fBvTegV`hLyU#dw(%Zu0KVsLS9P@nE5n92t3lG^iNE+=wX)QE^$K;m(x<;7)Mr zv~3Fv^p)`#U9oU|ZcDG{)?ceVSYVW|KB^42+XrSss?S=M7tDkwCeeIp4>)j{jJBe7az5e2YU6O6>{z= zJMp;=w~QNSGeOv;UVZ{%5tzpIv7rdz;tAnu8Fj-imIMnBdB>CND0TX5K1MCc!e@Tb zD>F0y#ojcuH8G9iCZgt`O@Ot5)OGT$21-;@=i#0+o_ch4$J%(AJ|DH*K`%7Bo5Yqd z^zed5rwjEH?37_u>SC$153ylJH_%24GzDfIgt{Q%mpmK4MyjzZpOLAB10C&4eosUW z{nzYQe0H8dv8d!im6ESYeiyKw6(Fj!up)mnJy&Cp8!G2KL@`-oHf@Vywn76*ZBE5{ zCR$_>AdB- z=%4_AB3(E(^~oCD-*G_Zy5DD7YIRL25pH)4y!?I$$@u09RqmbGGGFUQr zCJFmSxZbEEsz+4KB1IX=Jl37qSdtig+k(BoF%dVVR#_J{f8Du-8R^$)>0#%j3wrPj zk?Q2xb_re74+-#v>Uc;ueOH%?9hP#EMy^c85&!@I0=#MfZ2tZ&?ZPJp=ob_x6>I5R zqp|mlpEi#w4?gg26G@1yO3n&nFrosk+Y5s5AGR*M2s=-l;7@y4X|;A0u6nQ}r3eUb zuA7`%(HS-5LsMR|t6Fv)E!dCg^Pb}B+0a-l001Nu*jHq=?33H&Xc#%1T8K^w9Z@F& z^2ieE6a>e1BuwI^zCpmA>YyBKxHc7QR$KuGZ7-qAv&JAk<7e|E>B1)>%s3$*u%=MS zIW4FF0000267>)kdsrW%KVAFOpfEs9#{(dX=zK=O2iJExP~|H)DU8DCut?6>swa;T z9!i#r-ko_))drkUyRt_$a8Zc)YwMO5FPaX-&}g<=d?9B`6;a3mH{D@kgFuo3{Mk)% z3s08VyI@lw23PbjnGdfo>I7`Lz5JP{ctoZ4b zn8p8V#hE=?1u@;eNWM}Ra`M0IWI|d$C(&+~k=TuGpsU@c`WT?|iF}*z=;zLV0&}@l zl5L7;x$?+qz!t=jYXGRI#qDeuVAKGrQ)$?-;&7nrKs^Cgo)bzyVHSq`K<6!^ID^g} zh?1CWyM~{*Y!?CiX@JG`<-OuR{b9DArefMPu=f<-v;P^w zV-f8EKtnO1nNy2L%t+!m^NwZLDBk}<_U{LSU;ZQNxHYn3%`-*u2W9Z#UR-Lr*iQOE zrxeArWlIz{9}$c=;Qi}Ow(Uz6^AEGYR#XdiF?OD| z!~UN(DIl`R_6s3QY53C-dmscgWRmIJUIf0^(yQs{Dj$GJJxera%f&)|KQHstk)l*Y9AMhtB8e@ba!H#cKEa&hfwWAPDD2MvAzG=Hd-~M>!ik z5X94d9-ipR8n=zBb9lt!k@luC##d|6W*2GPWByGy_{9bCE2dLuGHT zHU_)Ke#4*#<=*9&?an_|gZHH`FS@V!&63{0@|QCchW3fCgL^qS6I>eLi8FlDed(xt zh_O%DM;E{Q58juPfZ z9;d~8Bl(Sjo!oc5Dp~s54)OFh3ug~Sx?Y$}jZ4G-Mu+qMdFpdi&MTbn;S>VGt~KKOEontFhGf{!(FRy0UySdQi)(b+DPyW559MSWipdAKARcUZ#! zScs5Q3pUOqV#0uO;bznimYXQ4KCnPqs{ENc5}GBc zp_srZ<89h-4q$Td1VgUi9&9AKJ%4*-m2#tO$c+=Mic@dVMhUMkpJ_dH`Z9rsHaK?M zg0K2jh)vM=E+u?oU7G&7`RLX~R$2eE2;G^qF3<>ZNPZ5FYIfwM_5F+61y zv!yya!eY%j*=QN>`(_xABH9Ur;W~U2G(;jYUB+e}Q^ZdZ+sH>gu(QhdR(rA3pTzaR zg_ia;b=iggVI?9QS1jp|tW^os`dZRY(1q2HG-n?J0jO5IAny^HG2Xea;T)1s5>H?0 z#pIluS%3z4#QPWdN@_jK%}YNr?H$$k8sqer>ogErj1(xX2+041+o+v38)DH%Dx*;_s}dHen}gXoEM|zW zzb92V))i(VlzxBzuZ8|WUEfS8V;bK*z#ygM)emzsMtqpyy;MxcmB z(?w81PN35+w%DLr<8$2I6u}p+(~Nj{2;IxNl%-BJqZ$kLI$OPl1ad9n;Vh@QwLv1s z31|R~=^%}^E>!s2SBS|9ULHMWDI^AT7(4EhFov-Qc=+mFqGeU~f%XE`u)sHygcw^* z9%j@R68;2~RNzK_MKNY5z3OILQG|M=fttFXf27zjRA(`duX@b42P^8&hoD!|d zhVcHg*%!(Q;Tro)W8`iDyC50jYIF{7GPWd9d<+6~?GqN&jFskzpFk@3MVcOp@INM) zusSV-WyHZ9`JFlIZ&DB6@5Z}j(g?(=;KPZKvbBAb(13(lU=M?}eY4k+SOp>LUkBIN z*A?9l8GXz<3z7p8$5T4Ia-V7;GeiK?y!GoLCS`jJo}WXxX`-T^J>kE&amX^Li+m<8 zyHu6NcU>8yyM&?cdn#+-%ytaZ3bxMktH}f~JqL?2=Cq9HP_|fJKm~>msUDjXv33M{ zINZ}3krj>Q#doN!hITGFgDq6{noh8?-&nV3cPVR4FSYb1Wc{N=g%@ETjtwTp4gV)i zRTu|w7iw1;B+Z%NRhtLO-qCqu_5=0X#&dq#qw%+z^|4&sGe`gc02O0U0{(;esX06& zCk+w6`1HlCc+v-f4DSp6K{IEjL$^8YXmxr9uSy+yasZVT0_JY(UrXwu)VTd9nYl`@ zh5gOB5K3KsvJFs{e|8xAuDyW6^JDdUmfj`Fe22!J7BN67Y0IJjQtfFaXPRHPCUW~rN%e7~G>2CY zpMR?OJ#cE3=w|_M_9sI=W)_`akto0prY@yYJBI-L_WByMm`vQ@yu2B92%oi6;eoJ@%AzBBoH5 zh+fV>GhsN*eKNEjA}xIq$Y(APyIz(|I+2P}SC9MD4n|kU@FfuZwQ4to?c8hf2}3KR zw<7#>n*&K#!UPr7APbLyUZ-qGptWy$T)Lbam5=1sr8A%@Di7mY9aM8q(vV$)pFo>| z9G?8DjJBtb3@4paJZ_Qiije)NpDUn|2u|>bj8lZv>qRFzyLWn`jmxgS%ZNYPTB}8| znWaBbBBsep?DEo=j$YlPBO1M8FN`I7%VddsIFQEQp5s@3jH*mW+Gz{)*=-7}W*5-$ z{W~iwt;;(aPBO*Q+~wGKEU%xHkv7@r!8|=b z88&~<FU( zI>2_Y==QSOJQsD8lJ12K5Nth+-17;|+C&`sfV|nn>`Spx2S`{&QvF>b>sY2hN`4q& z4`U(>HTFD|>gqa*W1(H1xF;W}QczMAtZM>qDAs|MPhv+^eF%B;M#&U^9U_q_Z;B0*y~_oM?TUX ze!fE1qDSny7m&3Foq@qFJ)kh|S!cdsLv3-1QGP63QslvcPn}yqT|!T*y0`kTNKc;b8;+S>M)JDG#gj8 z{r{QLz25+@=|zGV6G>2v2Rw50e@^ekU;(!;{w&F8?Ix43g=N^fQ-h1NpLnYt$kt)W zT`3ZQ=AU8Oxzfe=~M0Y!Z{VFCMXd@htYRXsunJyla>xBmVzDFe1+<#}__> zRe2VdV$RH_gm|m4xJF3V$0PSZo%}GMg(5R17F&;OI-?2TgBtMd7}!a@WBSKLpC=h* zMHsov2cgNvLWVd;YA-C7RtkrD`%WkOdF&vf$svDMY~8hl<-FQeH&Opua(?CZiyzTQ zu}+5kuqGckHnaO$QM}vr{`q&R(8R>?V63Qa#N9e4ydqC@-p53H)%eZY{`?MJ` zIIq1O+^+($&vEfLxX`-~FEfoqdBi(<2Is*74d#xS5Y6-0IuLAW#Gn44mKU)H+v9)5 zlfR`sVGp(ZLn>_Bs>~xLZ55d7hxMTYj%Pxczk5TZD7(jAHnJ0rZWra)lj%L}6Nbrv z4&q@2Aei+h_6|v8KwbK8t>VU_dXoDU?H0miWd*ol?Wn$8%=@eQHoS&dzcplXP4B95 zCceOI^9fGam4bqhd05Ex_oCces#;`}v*t-54+1laQtEOz4R3PKdSNt9f#~&fCTZ-5 zFMHTBFx8z%*Gl&#LFZVpy@p88yme+?NADbOS4_oVhNDY3AaM!N=}J_AYc!o>NTt$9 z%!jgIecY68j&p8f_Jnq`A`DfAbH}3!;t$a3I^Zgl-7n^iuk)T$Zb;nGqWY%4eCF}b z@9h{}2&M87-}y(u96kX8esA?CNh7t5oI#3lne*PdY+v%a;jw)?r2IR#HWF6e4mPIR zbTPp(Bp+zXfz*12S@n`#qY4|?`???g(@MU##OH})+OyvbpnmBWjSPC%V&2$?#$JWs zhf{iEn$G#HtXL)FDoMbo#I~I&R179&XLtlwMNj>w^O5Dsoz5l*sE zd=JM@{)VA;EC3K_-7a$tm}}RD&bx$r!Xwy$o9_Nb6g8dk_EA}V0w%UMagXMeqT1~u zg2paEjmGqHXSc9OIU)o|h09w((al2#MFrOwccUHOo)WPS*}`*YlTNqEC}Be{#vHG& zS~L@TtDgmIXm9=69gHWIS+jc$XJo?`)dpICob$^5#q|d4PSP@dpxZ~=!ITH4Z`2n% z3!#1{F`=32O1-Wev!54dsP zqsuj>$s|M-vq1C*kQA~lv|7qhG%hZo`{s5!xpAbm0BGk9-z#W6|Kv9kK_~Dt!<_UP zB7}EFOyDiim~SE4P;Tn@uPc2txc0PCU!gbMmTTct88fyp0s|B}^8LQM(^ z>Os7A^h5vv0009=-@XW?@FZQG(K@rj{N?StI)$@9&C!58@4RXN000Ge)Br$pL4@yZ z7;zoOQ=3At-H3As55hdo!S6ZYHbn+N&<`mU2n~WPE)x1ILA1tiguRMNt5-2< zDd+8UfI#e#Gry_IQ*qLN&P*1>HuR(~PT9vweg6${BH2Ghc^?=Gyrym*;a6gHtH8No zyMfW7EesL@7;R^Ec$cF!fu3WJPq>uU!%WS!K_6|Gh^$GVKRO7ZDkZ-r>@6_(0dj=W z^;1bRS#(5Y*o7v*hyzV1eA{Nb`~;C`=Pr-$miCH(mGShExiF<5Z+ENa0ufqpJdt|E z=nTv`Xj3EPp8Z``c6)MI%}|a{5uK^USs6fy9XQs(wxf!8?S|jDSPa<^Pzc;NGX`d1 zG5$5#n@^`$(60h@ol~7N#UlhM=nW6&z-mk!)RmvL%_Tw+=qN#O^od#C0000000V=yw{+z>RYF5tHzpXA9?)Q^pXli$k>Sl0zXZ|gYx?$i+ch1hvCy$-Y?GBV}E{c z=f{+{E%pRHz^~=7jMc_BJgC2n6fN`K@}c^HHIuzbly~wAIC+ggoS!Ajgrp&X<6=Cz z6{GUDTvSmKmi5%Z9&MZHOTStct-9ZiN0b@vEklKF;aM^vZ*B1f&~qYVzom@vA7bm} z|C`Lovc`Ciw2OfkTpefC*A<(c3yLXQX0*N=#9HX&rSvt(vT{8f!l4XQ5Yqs(qyT6s zbc;)q!KXhbPN_3fu}}yFJbjf^l`0 zAfWd-KIbcS*ODL9Sl*3zYce|yhanJS4`4yqpGHLh(zG36sPR)D)>n`C@qx>p1Z}=@ z-~a#s@mT;HLA$0L^p>#qubDuds7ndRY+LC>s1O6QTOWu3000IrjGHlR;Q!Q%_krzF z7>AEHe+MQRow`#lw`^7R8=pWe>DKfaiUOOR?l1bn?y9qaFAMi6000008V?eAs!VgE z)Aji0a??z%C0-$40vusEtpe1AAD10EcBE}J8Z&>OrKf4VKmjRbTL{akmcZ+M#!%S9 zpN?7@Ri=J+z3vpfhP03X0000L(Ld@EE+>I0I|fR~Wc9I4R-eRXfN@9F`IbZ~~nG zXbH7U0f~!K$1To-tVMMuFo+4%c_U_}u!8Gx6YFO{UFW4EdslPGLLTm=WW3ZpKZVL2!sM2Vy(f%9nSo~2j#*^R^x>(fyWA61CA8B2OKGM51xp5nfmgIelf!U{8FFp z8P6uIE6>;r?mX(ZHu13VwzhV)?tK4Ykw}A)Ek6iFpvuP-UDUEBStaca9J=Tp!&f74S+OnmMc>~^AR9#a&$FIydqrWhYp^@3LQK>L@Qp`o-~5W> zRFwyK8MyYUF}9D}ykrjbb}Vd#AutQxn6q3Bm*an_5g&7f0;D(e$FGye_=_L_002Vr zz=Jqk2fNxO!jFGI2s>xf`!_}T>(*D?b?8Z~PV%Fi<6$QuBawMI7aL zlFQB48#LD!9Ti-}A(q(iTu^{W;mULnud!T|2o6POkTMrNfs-{qg zr73=LMF9`?2O^5N%aukYz9%MBzm|Ly7iFhtDpNN|PXIRGgI}zG7!$`vwz0p%9KDB- zXCF87!PVRI{#>;bZox9sXd9sLHgQ~R4O9_Re5teavd0YJ9qykjBbwaAOU;0v8j$F@ zhgn_bT^A!OuE@)W%?8P#G7yWum);nUAhC%3 z9g&*(1qGDH@L$?JPCV}+c91vYiMk;oBUy$RHXi^qnW4%eDeD<2Wy&L9K-f zq?es6=b}k~kr~3Km5MC3(hs8G)#Q{!K@A*^kGHj}zO+<#w&OXXoIh!WHZ}y zHFR3)EdtHz!7&C3ka|}@?@GO+3k$<}!XNwazmm6%9=7{D8SOtWl0DCnH~Ul>bX)1Q zD8LFI&EZ|Ps`>P9GY%`;a-z-K_B0qZik?!n26L8IY!9qRbd+A6g!P8dVPY(v2{#1U?mq_ z(VLtk2Jm*UEvXc$eM%Hxob;_Cip^^&G)l95Xd_T>^v4Yo+3pU_b|NUpsA%;B>z=+w zUW0kq_;_WQcry!;JC%`$4Z(XOXOQ74oMkpj*vbKkn92Mf@|_+nNY;AFo`-@V7-5pwp zR`keNuJwa)IZp?c))x`v#cAJ9^kj=Njy}lseZpo)clH&cm$|KEVDry0TIXdl&glU6Cp$CFJSP>3*ql zMjVVD(nHndVgSY@q(>HPv^JeEUF?IT^k5N-te5tKe%X|g6N8L+INv_XXYAh9$ysYL zJAogwe@^7l+IR`^RNZk7H`8vc(nR!X0Q$o~EXiqyvW>%0OPSzVmRmSFYK8iR+zNyL zZVL+|X8DsV;060c+7!4Af#a?SiKEM-sI2=1ra}mO5?{7Og-|I#x;2Q54KWeNb_|pW zYO)~XsOEcT59{F#JQuopNYjxG9@f69i9iL|!`dEk|BlT1i+ z)nKyuI65nEu$>~OQOKzHtD<@w8KLN30MqPBN zh6{%XD8ydcmzSFvOAwt|EeeHX}$;@$TqwubXYPW^P-Ae3#4}3GfaGoPjcp5||Eg zU6VNKzf}RH6|)d^N{|#M0Jw?R2t%dTTKuQ)o^Bg}k@BzuSMB*8s|rG3=0b&N_^9M& z?s$SdQI1WB@Ypd~>^1L*RQ8}!OiRrw**&Js{E>MPI&FG_ZDP~1qOB4*#|~KD>_>*| zbDTq~zltc}004i?q=(u`cDN-t!5HEh%NbL}l&n(ni>G3rEvISTt*&B(DgWiQ^7bX* zV9G`vuI)S*L9D&0fZXDqe^9ED81gB6lDX0UDAT89XnvA{`IZ{k@fn~7@|_{bVa5Ft zSr&HeACA4aI*z(6%>5dGBA+m@O|*89Lpdt;m!D=Eavb&S2c<0i8Nia`R+Tfsbjzp) z;fCVmKHH}Q&!m99$5Etpgx?9URNPOJTU-%ma*RDwgT%Yvy~ZuTR%Mwtk{%08l-2aw z%ocG`a5qi}nUJT;fCIpBJ}Gl4VM4k=M<8+L$&;BjZ<-V42A64Dfi%wBLkziq=@d6H z{j7!BE&;r@wp4(y#D*ARi4gT%(|}gYxF7%E`*lQAnX&i7<1&) zRUA->%Kd1iL@}nv?Q}{XdT_cClINfTRZsNPnfhH(IGRZjhJ51kki$ zEdjonCWRp?sUVDza<5+8_jW8yoH%%kQxekA0VglnyKd8d8FMQDWp=y`@xo{md!Xb_ z2tfE4E!e!wgk{XTBeed`7_;$B6XZ7!W10AAK;RBH6wLHhuoBO2ZJ(gQ(h&-#Wf$Vz ztx&ADxHSjMf(wjPz9yK$Xh1wN1PwQI0AMUFF?p6EiA2{){;qzJnec^D*iA~Y75z-zl z41kQ^VP$3F!)ZV=Osj)~+sqXGSxL|>|H^OtdC$H0Mst0iO&9P(akB<#e@*0Q zEwHcp_kl`iWa5yBE@Z8Zr&;R?bsUO?>`TKBbkp_czu>Gix&KMdVmGE1dgwW&CEK0L zlWrRkPre5du5(rd+hb!qiq$VUb0)n$>p_BiF4+FrQ>;}559yb<5Tok?xA?~82U;e4 zCQVSvY}9-v!053KOwQf+6(5fAzoXBFW#$ugGu`;b2Td4{H;ib*`Ks&5uk;bf475AV znt%xny;wD>$*qn7;cdIo=WY?X%&e)*62Bem$u(6JT@?`N^)Qv5q1hY6`cOWc9_DFZ zpO>{W*qSmEPAMEZbAwvNK>lIy za;3{fg8vzT)6U%Mq)D`(N1@QGuO+|a04w)_i2-VNRuH2A+S7m`7l;l300000000Sk zY3Vz@tA1BG+&+hOr*mZ7x61nI?R-AAlo*dpL}x zLcNGL3_wuP?*H~R80(Jbtpm{{VY|H2Rjtc@K7CzHdhf4VD~%eeDa*{tSX;tAhawRE z&(b%Z_SUs<)maFp1|4H71}ShBiRK~W1PI<{m(tuZlSVR}d0V~+U;%;y1puc5isxm( z8g!ILM{U&my6~TRJSg%Tv1Tg zqc5=~CQh!&Ajc7rN0$QWme2qd;N`M+kAMrWi4VjcMoIIz<=UAT|0N36yT`%5D3)|O zL!i&P1+76!Ap#^8++<3uNUEU2k^foJR4T_8-!jG~OK!LQ@+1!AOqZ-*q5M5~X3TPA_Cjpkk;aAzNmSE)f$J;@4mk##W@!(a|#hP`D{pU`>)pNxtgH!PsfY zSVdtYs3fll*ZY7w;6xB+DsVzK%H?1hYrfdiBIKkLw-Q2p)M`0&%*4YUedWlKfDaw& zE)YATuKa#%PlYAtvTeWo852z5k0OMaxcNQSG_3#t00+ioiu#A^nIbUgr`=j3q!*vG zyK#>N#@?B2K!cAA^MGa17}PgdQ@u-;n)t=D2Zd+G6;xAIr?y}K_~7KAvIO3vRauq7 zpOECmdj}+0J~NOF|D^)=kcxf59d!BOe+}xc+ZZKOpzBy9*^UFxSb%U4r`G;V(U>4$ z1&G4U%$lwa)|dXnyO_zH3V&V6RG$q!b!T9r%rJn_*y&SLSA>#J5yZj0qjk6hrIknW zae?FD+l6@>k>E+bN$7DQXCH;GWRR#l0HZl@00000iUbLQ{-u8DZFyCZebKf&7&$7< zyltm&!{pH?UX%i3sm6io3-Y9YP9yf^H@mG#IBB9@i!TOn zVU~?2a!NVz15ub|snJP7*I%XWiT==t(1s zbW*^TLKXl302R_;&;YfaIVihJmXqeKPQmWVaXSUX#|Ak`fw4>bRF@Q#BZDL_h~W#_ z)Gmo5r*-*lp56_+_JVYJ>7cUf4p|)@vUFCVBbdgG)t#@-uJMD<)MV{Kx9(K$AWYwS z5CRbFY!4b@m!AbUU;CN_XCUN{v;ed8Pc$06rj!VNI1$VZ45x z1O9XJvrn@M~vwL z?#4mQNJeS#KRdUdLQ#(RMq~N^8L#PSvt)7?tR3Ei{t>}-U)waOkuC$!CY*{1`1OsK zc|T)z6AI@J2+F-9c_GApu*plf?(4j>Ze9_O>FG_nX+)VQ7g(JfK^C{Vl)BqMo)gWv zom~J2j}5wE%G%!;EppGA@3u6$?+{Q>y9pT~`pV4zT!v35000000cY)S9cH^B30|M) zU;WE0$T3ROVnv~=riukf!Qu1pq3sna85sP?aw5r@Ig#vCI@Iw9&xa(*W=YXwx6p<^ z#{hhYuH45GgwXHQmx;MH=*TW4SNE>Uka!307(D$j{r>Gkebh9xs3Gw?TU7>{Z}(~& z+=mN4=aB32>8HezLcc66b3nN&yQ0|!Ki4}of{uP_!u=gk=gm{#>;T2imVb+Q_6Ls>`|=0sJts`y!#pHJ`=J?%s9vbj z79bazHVQGqbi)arZK^5`+X)8w<;o=qx?&=e5fGoa%7H<%#k9dnOp_Gkg97Tolkv1{!!bfOER&ZUuP0D(x5FV@f;GnEP6t?YC( zHcLZ(erIkpe65{V3oU~{1s#m>2Qv2eOxoXdGe9jWWs!u2>$|0Z}hFw2Ac9>zt#BU@q8JA(0mLO~71Q&C7kC1ZEIRram@M3$qhI6u>?%f<1 zBYrJ+cTmoDQl)aLH)e7k-Eloj)tJsG4MEdK$8)TciHdgs(zLS5+eNNMn@F`=@Aj*v z8Zh7Ah!MktZJh?ul|$7KY9y7R%HuFH8hn2}#=@@Ny$$B_LuhOH^wLD8e$YbIYIW|o zgPP*Y#Aa}Jjhcvfdq0odB=}C>d_J`s5vn~{cPMPX@PNPo0036WV8DSm)`$^GLMq`= z(A`h^`xMN!qo3iVzuX+tY6+E^Y;lmr2Avk>e0m&(mp^xV1;)>qBW5`pLn3iFLEVMZP}58X^OM`21XN zxHf<8;l@ivROtsB@7#?2W=Tm;EO@$c3&Eakv;)5&)zCztQb&@{?h_(?Yoytc3zWnB zL+4SjfB*mhDYmDGm872f_NX(En912)%B-DZuP9y9t(R?cFYjgBwr$(CZQHhO+qP}n z@4la(aB`AP=GX4bq^i1V)HRHzq{{b`)vrl`S=57w5Im~70?!AfeHVB2erCY&N1^1# zEEg*rx`HclA2eJ!;ms6kt!<1N2n0=g7d-%&pqM#QthQ`ClV06rx7OW0hpPRzX9Z6a zhBhL52{q(?UrWQWjR1}3v{>{IB}?3|c=OG$Wt>4%k57z*Xw3ot+Ebw`okEvJ$cpEo z{CJ4PCPt#>q(&Jf6aL~8!N-;i%Jp7sFJX*|;jdEQf_&B%ae zZV4)18KW489s@}xUMv5p`)!IH^<}kK@^5(^RkRL=F~;V3%Ebi9fP-uJ;=0iMdRlV6 zV3*@e`8;i+R12_C&%(__h7vda;O*NeekA4W)1&~i+IYLX0Vv@cwUiusR~o$1M-rZL zdboB+doKAjfG6Q9IpDV{cIO_h&1r7|EAk(GFNp)<^G|@ow6bZ5YnqEWn?y{2c*0;* z;?#pE{j+1hDi(L>KN;{{72hJ*=z9}yME7Sc?LayM^1jV7gU4T(G;_t$N9G4r4_!AM z9l3U^0Y@E;Ji7581}`66z90P`8l@>9E}oCy$-&|`0f{sf^krZT%ec75xd4SJ3DQ6AUfz?&Cx5MT zZcL*y8taT{;hl*T`X?HOpOzI=r>~Xwvb-ko03=Rn7IfW1UX1(@a9wy*dn`yonwhGn~zT#gh`PnAIXlzqnTH#VF6Ix9HJCw2|t4A*fxsMbduSN zA+t&jl93q4wBD%bBE%rVMwmMgqm!jFNN!0C3hsk-VAA2vTqJhNRw0g7aDi6g^GpA)|@Lv-t*)B3j;_X>lP*VD@~a`w>v zV@?@-^^>DZps7YB?$WCY6nV7O-IRYh{_xEK*yyKib>8aL+ z!yyLc+o}e9_k8B!WAHIZ>aP~I3L-3--m8)25K+AbHjGF|Odvx22FW}w7=dAvWB~_^ zz^HkT+(_leA}^_m`)Pf1X}@TpE5KCZI0gpvF$ip9R#ZImufk?`cC?$To6)SnQ>+w8 znI-c}bl?oxO5^GNQ=Kf%wvZ_%81Wkt3G~Eosg+CKNhN7zwp_q9)XhIv zLXSz+Py)BjBf^ssqWrq44F*SYTp?`Gr+at2=?S-4?cS0#@CbF(wiTscAxYL`#>sA5 zo+5tTOVilIB+$Qz#6o4@8TtYd=tc8nurWB=vtcMf)6ghg9!D^KRu;aZF~>_?Go(d& znvO>;vV~BZc81JMN0z5tcKX5tEYMQwvMH)H1UJMuy`^zs1-M|ZQSx~ zEu=V3wRKq9yM2#aukNfJi;nvQ4mdjXrphBpVt=6kK=^HqntN3DQx8j4IEaQb4h`p^ zXuZf5M;KN$&J1O`r)?OZKj|;6Y$EbQ+T{b9HdUg67^nWdrP!|CRK7#Nj1PcmtG_LT zKAG8#05IV!AtJHA83352*?%$Ul|T+>uNRbsHjZ48s%H%qVFazK@*&C8hJV98Ae0n_ zt1%6e1DfZ_I^;rG6+#wNxGANHopG~0mK9BKu5?Gab0AJvMqGl+{kToHvKxNTr(kl@ z?ZnU3OGfVN5qUX|W<@*Yt^;QXZrZ^#cszboMEf`02p+^Gvgn@v0bCEd)i<+HjclaZ z0R?@&E7(@?{1vOKG}AJ=SQ=V zn!g9q(w{Bju(aJI zYp2y5(X#mxGi|<@?0`suJIE;})+RvA`7A>jVh+@P-cd1LwqlsvD_d(U#mLX3+1(W%_fwi8xym4KA!|zML&A?PWmlR z$m0r5BBrav{6RQ+SYN6Aub6H5OZ39~^d`Cw&bzA!+O;cn;s{8fRARm7K5E+EO7pIOF##h0omW~yG z{Rk{SC7q{Wfy*P2nS$XbE2z=}d6iFU%Dn#GuEjl4oV0(f(ZS!a$HY?PP?=~g!jK=` z{Lb=_s?c^d-fT9ImiZ3ICxfA&p%MddzkCm?8{59a9%mCFrfM=N>|*ihr6%phhkd$V z9We19%hly%5CT}kws=}^f^3=#lQeYI;RmHtAb(7s7QpS#=eb<+Pp9{8e zNRSn}Y$4eSpR2sVGN`Xny-I&jhqNL8!zMBpu>9yo&}?BzvA~jV2ztP!-E#l!jF$

8&`7Q1}O+{s+T6T5F>Pq&*LVj}n_+Jglo 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 literal 0 HcmV?d00001 diff --git a/docs/public/assets/img/favicon.ico b/docs/public/assets/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3004211b1271c3e8e3d1c436f69998ea386d7278 GIT binary patch literal 15406 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 Q4bOxAMt_sQPnN*{0<3B!w*UYD literal 0 HcmV?d00001 diff --git a/docs/public/assets/img/logo-black.svg b/docs/public/assets/img/logo-black.svg new file mode 100644 index 00000000..6e2ea3bb --- /dev/null +++ b/docs/public/assets/img/logo-black.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/assets/img/logo-plum.svg b/docs/public/assets/img/logo-plum.svg new file mode 100644 index 00000000..ea6f8696 --- /dev/null +++ b/docs/public/assets/img/logo-plum.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/assets/img/logo-white.svg b/docs/public/assets/img/logo-white.svg new file mode 100644 index 00000000..739a8cea --- /dev/null +++ b/docs/public/assets/img/logo-white.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg new file mode 100644 index 00000000..cba5ac14 --- /dev/null +++ b/docs/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/sidebars.json b/docs/sidebars.json new file mode 100644 index 00000000..ce1e023e --- /dev/null +++ b/docs/sidebars.json @@ -0,0 +1,47 @@ +{ + "main": [ + { + "label": "Clients", + "items": [ + { + "label": "GRPC", + "autogenerate": { "directory": "client/grpc" } + }, + { + "label": "TCP", + "items": [ + { + "label": ".NET 21.2", + "autogenerate": { "directory": "client/tcp/dotnet/21.2" } + } + ] + } + ] + }, + { + "label": "Server", + "autogenerate": { "directory": "server" } + }, + { + "label": "Cloud", + "items": [ + { + "label": "Overview", + "autogenerate": { "directory": "cloud" } + }, + { + "label": "Dedicated", + "autogenerate": { "directory": "cloud/dedicated" } + }, + { + "label": "Shared", + "autogenerate": { "directory": "cloud/shared" } + } + ] + }, + { + "label": "Tutorials", + "autogenerate": { "directory": "tutorials" } + } + ] +} diff --git a/docs/src/assets/fonts/Solina-Bold.woff2 b/docs/src/assets/fonts/Solina-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..813770ef1b25aacbadc5215c9fe8d322a146ddea GIT binary patch literal 16364 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 aMlDuRruCI-0rUb}wj_)C#52~H(+F1;1H&l* literal 0 HcmV?d00001 diff --git a/docs/src/assets/fonts/Solina-Medium.woff2 b/docs/src/assets/fonts/Solina-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..8598d1216ef40c352a31a72039931a31ba6e9d2d GIT binary patch literal 16148 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

p;j-aF1zH6vsc>Zs`I9Z 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 literal 0 HcmV?d00001 diff --git a/docs/src/assets/fonts/Solina-Regular.woff2 b/docs/src/assets/fonts/Solina-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..29565392eedd536882ca26a9432b3bb7d3a0ccdd GIT binary patch literal 16312 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

L5}!wbyJzinby~Y}wl*>_uq3k6=ZVq4m$0sq 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 Q4bOxAMt_sQPnN*{0<3B!w*UYD literal 0 HcmV?d00001 diff --git a/docs/src/assets/img/logo-black.svg b/docs/src/assets/img/logo-black.svg new file mode 100644 index 00000000..6e2ea3bb --- /dev/null +++ b/docs/src/assets/img/logo-black.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/assets/img/logo-plum.svg b/docs/src/assets/img/logo-plum.svg new file mode 100644 index 00000000..ea6f8696 --- /dev/null +++ b/docs/src/assets/img/logo-plum.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/assets/img/logo-white.svg b/docs/src/assets/img/logo-white.svg new file mode 100644 index 00000000..739a8cea --- /dev/null +++ b/docs/src/assets/img/logo-white.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/assets/styles/buttons.css b/docs/src/assets/styles/buttons.css new file mode 100644 index 00000000..9467af80 --- /dev/null +++ b/docs/src/assets/styles/buttons.css @@ -0,0 +1,30 @@ +.sl-link-button { + @apply flex items-center justify-center rounded-xl px-5 py-2.5 font-medium tracking-tight transition-(--button-transition-properties) duration-300; + @apply focus:outline-none; + @apply disabled:pointer-events-none; +} + +.sl-link-button.primary { + @apply border-primary-600 from-primary-700 to-primary-700 relative border bg-gradient-to-t text-white; + @apply before:bg-primary-500 before:absolute before:-inset-0.5 before:-z-10 before:rounded-full before:opacity-0 before:blur-sm before:transition before:duration-300; + @apply dark:hover:border-primary-300 hover:before:opacity-100; + @apply focus-visible:ring-primary-300 focus-visible:ring-4; +} + +.sl-link-button.secondary { + @apply border-base-300 bg-base-50 text-base-800 border; + @apply hover:bg-base-100; + @apply focus-visible:ring-primary-500 focus-visible:ring-4; +} + +.button--outline { + @apply border-base-400 text-base-900 dark:border-base-600 dark:text-base-100 border bg-transparent; + @apply hover:bg-base-800 dark:hover:border-base-100 dark:hover:bg-base-100 dark:hover:text-base-900 hover:text-white; + @apply focus-visible:ring-primary-500 focus-visible:ring-4; +} + +.sl-link-button.minimal { + @apply text-foreground/80 bg-transparent; + @apply hover:bg-base-200 hover:text-foreground dark:hover:bg-base-900; + @apply focus-visible:ring-primary-500 focus-visible:ring-4; +} diff --git a/docs/src/assets/styles/custom.css b/docs/src/assets/styles/custom.css new file mode 100644 index 00000000..db3b9a51 --- /dev/null +++ b/docs/src/assets/styles/custom.css @@ -0,0 +1,146 @@ +:root { + --sl-font: 'Solina', serif; + --sl-color-text: var(--color-base-100); + --sl-color-text-accent: var(--color-plum-200); + --sl-color-gray-3: var(--color-base-300); + --sl-color-bg: #000000; + --sl-text-xs: 0.875rem +} + +:root[data-theme='light'] { + --sl-color-bg: var(--color-base-50); + --sl-color-text: var(--color-base-900); + --sl-color-text-accent: var(--color-plum-500); + --sl-color-gray-3: var(--color-base-600); +} + +picture { + display: block; + margin: 2rem auto; + padding: 1.5rem; + background: var(--sl-color-bg-sidebar); + text-align: center; + transition: all 0.3s ease; + width: fit-content; + max-width: 100%; + cursor: default !important; +} + +picture:hover { + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + transform: translateY(-2px); + cursor: default !important; +} + +[data-theme="dark"] picture { + background: var(--sl-color-bg-nav); + border-color: var(--sl-color-hairline-light); +} + +[data-theme="dark"] picture:hover { + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3); + cursor: default !important; +} + +picture img { + max-width: 100%; + height: auto; + transition: opacity 0.2s ease; + cursor: default !important; + display: block; + margin: 0 auto; + border-radius: 4px; + pointer-events: auto; +} + +picture img:hover { + opacity: 0.9; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); + cursor: default !important; +} + +[data-theme="dark"] picture img:hover { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4); + cursor: default !important; +} + +.sl-markdown-content picture { + margin: 2rem auto; + display: block; + width: fit-content; + max-width: 100%; +} + +@media (max-width: 768px) { + picture { + margin: 1rem auto; + padding: 1rem; + width: fit-content; + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +picture { + animation: fadeInUp 0.5s ease-out; +} + +picture source { + pointer-events: none; +} + +picture { + line-height: 0; +} + +.starlight-image-zoom-control { + display: none !important; +} + +img[data-zoom="off"], +img[data-zoom-disabled], +starlight-image-zoom-zoomable img, +starlight-image-zoom-zoomable, +starlight-image-zoom-zoomable picture, +starlight-image-zoom-zoomable picture img { + cursor: default !important; +} + +img[data-zoom="off"]:hover, +img[data-zoom-disabled]:hover, +starlight-image-zoom-zoomable:hover, +starlight-image-zoom-zoomable:hover img, +starlight-image-zoom-zoomable picture:hover, +starlight-image-zoom-zoomable picture:hover img { + cursor: default !important; +} + +[data-starlight-image-zoom] img, +[data-starlight-image-zoom]:hover img { + cursor: default !important; +} + +picture * { + cursor: default !important; +} + +picture { + transform-origin: center center; +} + +picture img[data-zoom] { + cursor: zoom-in !important; +} + +picture img[data-zoomed="true"] { + cursor: zoom-out !important; +} \ No newline at end of file diff --git a/docs/src/assets/styles/global.css b/docs/src/assets/styles/global.css new file mode 100644 index 00000000..8cfaeafe --- /dev/null +++ b/docs/src/assets/styles/global.css @@ -0,0 +1,7 @@ +@layer base, starlight, theme, components, utilities; + +@import '@astrojs/starlight-tailwind'; +@import 'tailwindcss/theme.css' layer(theme); +@import 'tailwindcss/utilities.css' layer(utilities); +@import "./tailwind-theme.css"; +@import "./buttons.css" layer(components); diff --git a/docs/src/assets/styles/nav-links.css b/docs/src/assets/styles/nav-links.css new file mode 100644 index 00000000..e97c59fb --- /dev/null +++ b/docs/src/assets/styles/nav-links.css @@ -0,0 +1,51 @@ +/* Custom navigation links in header */ +.custom-nav-links { + display: flex; + align-items: center; + gap: 0.5rem; + margin-left: 2rem; + flex: 1; +} + +.custom-nav-links .nav-link { + display: block; + text-decoration: none; + color: var(--sl-color-text); + font-weight: 500; + font-size: var(--sl-text-sm); + padding: 0.375rem 0.75rem; + border-radius: 0.375rem; + transition: all 0.2s ease; + white-space: nowrap; +} + +.custom-nav-links .nav-link:hover { + color: var(--sl-color-accent); + background: var(--sl-color-accent-low); +} + +.custom-nav-links .nav-link.active { + color: var(--sl-color-accent); + background: var(--sl-color-accent-low); + font-weight: 600; +} + +/* Hide on mobile */ +@media (max-width: 768px) { + .custom-nav-links { + display: none; + } +} + +/* Adjust spacing on medium screens */ +@media (max-width: 1024px) { + .custom-nav-links { + margin-left: 1rem; + gap: 0.25rem; + } + + .custom-nav-links .nav-link { + padding: 0.3rem 0.6rem; + font-size: 0.85rem; + } +} \ No newline at end of file diff --git a/docs/src/assets/styles/tailwind-theme.css b/docs/src/assets/styles/tailwind-theme.css new file mode 100644 index 00000000..168be0a4 --- /dev/null +++ b/docs/src/assets/styles/tailwind-theme.css @@ -0,0 +1,122 @@ +@theme { + --color-plum-50: #fcf3f8; + --color-plum-100: #fae9f3; + --color-plum-200: #f7d3e8; + --color-plum-300: #f2afd5; + --color-plum-400: #e97db8; + --color-plum-500: #de569d; + --color-plum-600: #cb377d; + --color-plum-700: #b02663; + --color-plum-800: #912352; + --color-plum-900: #631b3a; + --color-plum-950: #4a0d27; + + --color-primary-50: var(--color-plum-50); + --color-primary-100: var(--color-plum-100); + --color-primary-200: var(--color-plum-200); + --color-primary-300: var(--color-plum-300); + --color-primary-400: var(--color-plum-400); + --color-primary-500: var(--color-plum-500); + --color-primary-600: var(--color-plum-600); + --color-primary-700: var(--color-plum-700); + --color-primary-800: var(--color-plum-800); + --color-primary-900: var(--color-plum-900); + --color-primary-950: var(--color-plum-950); + + /* base colors */ + --color-base-50: var(--color-neutral-50); + --color-base-100: var(--color-neutral-100); + --color-base-200: var(--color-neutral-200); + --color-base-300: var(--color-neutral-300); + --color-base-400: var(--color-neutral-400); + --color-base-500: var(--color-neutral-500); + --color-base-600: var(--color-neutral-600); + --color-base-700: var(--color-neutral-700); + --color-base-800: var(--color-neutral-800); + --color-base-900: var(--color-neutral-900); + --color-base-950: var(--color-neutral-950); + + /* Generated accent color palettes. */ + --color-accent-200: var(--color-plum-300); + --color-accent-600: var(--color-plum-600); + --color-accent-900: var(--color-plum-900); + --color-accent-950: var(--color-plum-950); + /* Generated gray color palettes. */ + --color-gray-100: #f5f6f8; + --color-gray-200: #eceef2; + --color-gray-300: #c0c2c7; + --color-gray-400: #888b96; + --color-gray-500: #545861; + --color-gray-700: #353841; + --color-gray-800: #24272f; + --color-gray-900: #17181c; + + /* other theme settings */ + --color-dark-bg: hsl(0, 0%, 1%); + --button-transition-properties: box-shadow, color, background-color, border-color, text-decoration-color, fill, stroke; + + /* layout settings */ + --screen-xs: 400px; + --screen-sm: 640px; + --screen-md: 768px; + --screen-lg: 1024px; + --screen-xl: 1280px; + --screen-2xl: 1536px; + + /* font families */ + --font-fallback: + -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, "Helvetica Neue", Arial, "Noto Sans", STHeiti, "Microsoft YaHei", SimSun, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-mono: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", "monospace"; + --font-sans: Solina, var(--font-fallback); + + /* starwind and cosmic themes animations */ + --animate-accordion-down: accordion-down 0.3s ease-out; + --animate-accordion-up: accordion-up 0.3s ease-out; + --animate-marquee-integrations: marquee-integrations 100s linear infinite; + --animate-marquee2: marquee2 70s linear infinite; + --animate-marquee-testimonials: marquee-testimonials 60s linear infinite; + --animate-borderRotation: borderRotation 10s linear infinite; + --animate-flash: flash 5s ease-out infinite; + + --radius-box: 0.5rem; +} + +/* "inline" option is necessary here https://github.com/tailwindlabs/tailwindcss/discussions/15122#discussioncomment-11356322 */ +@theme inline { + /* starwind utilities setup */ + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-dark: var(--primary-dark); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-info: var(--info); + --color-info-foreground: var(--info-foreground); + --color-success: var(--success); + --color-success-foreground: var(--success-foreground); + --color-warning: var(--warning); + --color-warning-foreground: var(--warning-foreground); + --color-error: var(--error); + --color-error-foreground: var(--error-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-outline: var(--outline); + + --radius-xs: calc(var(--radius) - 0.375rem); + --radius-sm: calc(var(--radius) - 0.25rem); + --radius-md: calc(var(--radius) - 0.125rem); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 0.25rem); + --radius-2xl: calc(var(--radius) + 0.5rem); + --radius-3xl: calc(var(--radius) + 1rem); +} diff --git a/docs/src/components/CustomSidebar.astro b/docs/src/components/CustomSidebar.astro new file mode 100644 index 00000000..b84c2623 --- /dev/null +++ b/docs/src/components/CustomSidebar.astro @@ -0,0 +1,554 @@ +--- +// src/components/CustomSidebar.astro +import type { Props } from '@astrojs/starlight/props'; +import { getSidebarConfig } from '../utils/sidebar'; + +const currentPath = Astro.url.pathname; + +// Get dynamic sidebar configuration +const { sidebar: dynamicSidebar, versionInfo } = getSidebarConfig(currentPath); + +// Transform sidebar items to Starlight format +function transformToStarlightSidebar(items: any[]): any[] { + return items.map(item => { + const transformed: any = { + label: item.label, + }; + + if (item.link) { + transformed.href = item.link; + } + + if (item.items && item.items.length > 0) { + transformed.items = transformToStarlightSidebar(item.items); + } + + if (item.collapsed !== undefined) { + transformed.collapsed = item.collapsed; + } + + return transformed; + }); +} + +// Use dynamic sidebar +const sidebarItems = transformToStarlightSidebar(dynamicSidebar); + +// Get version switch path +const getVersionSwitchPath = (targetVersion: string) => { + if (!versionInfo?.isVersioned || !versionInfo.currentVersion) return currentPath; + + // Replace current version with target version in the path + const versionPattern = versionInfo.currentVersion.startsWith('v') + ? new RegExp(`/${versionInfo.currentVersion}(/|$)`) + : new RegExp(`/${versionInfo.currentVersion}(/|$)`); + + return currentPath.replace(versionPattern, `/${targetVersion}$1`); +}; + +// Helper functions for active state +function isActive(href: string, currentPath: string): boolean { + if (!href) return false; + + // Normalize paths for comparison + const normalizedHref = href.endsWith('/') ? href.slice(0, -1) : href; + const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : currentPath; + + // Exact match + if (normalizedPath === normalizedHref) return true; + + // Also check if the current path is a sub-path of the href + // This helps with index pages + if (normalizedPath === normalizedHref + '/index') return true; + + return false; +} + +function hasActiveDescendant(item: any, path: string): boolean { + if (item.href && isActive(item.href, path)) return true; + + // Check if any descendant is active + if (item.items) { + for (const child of item.items) { + if (hasActiveDescendant(child, path)) return true; + } + } + + return false; +} + +// Generate unique IDs for each sidebar section +function generateItemId(item: any, index: number, parentId: string = ''): string { + const base = item.label.toLowerCase().replace(/[^a-z0-9]/g, '-'); + return parentId ? `${parentId}-${base}-${index}` : `${base}-${index}`; +} + +// Check if we're in mobile view +const isMobile = Astro.props.isMobile || false; +--- + + +

+ + + + + \ No newline at end of file diff --git a/docs/src/components/ThemeAwareImages.astro b/docs/src/components/ThemeAwareImages.astro new file mode 100644 index 00000000..f6d1678b --- /dev/null +++ b/docs/src/components/ThemeAwareImages.astro @@ -0,0 +1,118 @@ +--- +// src/components/ThemeAwareImages.astro + +export interface Props { + light: string; + dark: string; + alt?: string; + width?: string | number; + height?: string | number; + class?: string; +} + +const { light, dark, alt = "", width = "800", height = "600", class: className } = Astro.props; + +// Build style object for dimensions +const imageStyle = { + ...(width && { width: typeof width === 'number' ? `${width}px` : width }), + ...(height && { height: typeof height === 'number' ? `${height}px` : height }), +}; + +const styleString = Object.entries(imageStyle) + .map(([key, value]) => `${key}: ${value}`) + .join('; '); + +// Check if images are SVGs to handle them differently +const isSvg = light.toLowerCase().endsWith('.svg') || dark.toLowerCase().endsWith('.svg'); +--- + +
+ {isSvg ? ( + <> + {alt} + {alt} + + ) : ( + <> + {alt} + {alt} + + )} +
+ + \ No newline at end of file diff --git a/docs/src/components/ThemeSelect.astro b/docs/src/components/ThemeSelect.astro new file mode 100644 index 00000000..9c03c219 --- /dev/null +++ b/docs/src/components/ThemeSelect.astro @@ -0,0 +1,169 @@ +--- +import Sun from './icons/Sun.astro'; +import Moon from './icons/Moon.astro'; +--- + + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/components/icons/Moon.astro b/docs/src/components/icons/Moon.astro new file mode 100644 index 00000000..eab5d5ef --- /dev/null +++ b/docs/src/components/icons/Moon.astro @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/src/components/icons/Sun.astro b/docs/src/components/icons/Sun.astro new file mode 100644 index 00000000..6ebaf9a9 --- /dev/null +++ b/docs/src/components/icons/Sun.astro @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts new file mode 100644 index 00000000..b43a70a1 --- /dev/null +++ b/docs/src/content.config.ts @@ -0,0 +1,23 @@ +import { defineCollection } from 'astro:content'; +import { docsSchema } from '@astrojs/starlight/schema'; +import { glob } from 'astro/loaders'; + +// Custom function to preserve dots in slugs and normalize to lowercase +function generateId({ entry, base }: { entry: string; base: string }) { + // Remove the base path and file extension, but preserve dots + const relativePath = entry.replace(base + '/', '').replace(/\.mdx?$/, ''); + + // Convert path separators to forward slashes, preserve dots, and normalize to lowercase + return relativePath.replace(/\\/g, '/').toLowerCase(); +} + +export const collections = { + docs: defineCollection({ + loader: glob({ + pattern: '**/*.{md,mdx}', + base: './src/content/docs', + generateId: generateId, + }), + schema: docsSchema(), + }), +}; \ No newline at end of file diff --git a/docs/src/content/docs/client/grpc/appending-events.mdx b/docs/src/content/docs/client/grpc/appending-events.mdx new file mode 100644 index 00000000..d7b2d6d3 --- /dev/null +++ b/docs/src/content/docs/client/grpc/appending-events.mdx @@ -0,0 +1,92 @@ +--- +order: 2 +title: "Appending events" + +--- + +import typescript_append_to_stream_appending_events from '/src/content/_samples/clients/node/6.2.1/appending-events.ts?raw'; +import typescript_append_duplicate_event_appending_events from '/src/content/_samples/clients/node/6.2.1/appending-events.ts?raw'; +import typescript_append_with_no_stream_appending_events from '/src/content/_samples/clients/node/6.2.1/appending-events.ts?raw'; +import typescript_append_with_concurrency_check_appending_events from '/src/content/_samples/clients/node/6.2.1/appending-events.ts?raw'; +import typescript_overriding_user_credentials_appending_events from '/src/content/_samples/clients/node/6.2.1/appending-events.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + +When you start working with KurrentDB, it is empty. The first meaningful operation is to add one or more events to the database using one of the available client SDKs. + +:::tip +Check the [Getting Started](getting-started.md) guide to learn how to configure and use the client SDK. +::: + +## Append your first event + +The simplest way to append an event to KurrentDB is to create an `EventData` object and call `AppendToStream` method. + + + +`AppendToStream` takes a collection of `EventData`, which allows you to save more than one event in a single batch. + +Outside the example above, other options exist for dealing with different scenarios. + +:::tip +If you are new to Event Sourcing, please study the [Handling concurrency](#handling-concurrency) section below. +::: + +## Working with EventData + +Events appended to KurrentDB must be wrapped in an `EventData` object. This allows you to specify the event's content, the type of event, and whether it's in JSON format. In its simplest form, you need three arguments: **eventId**, **type**, and **data**. + +### eventId + +This takes the format of a `Uuid` and is used to uniquely identify the event you are trying to append. If two events with the same `Uuid` are appended to the same stream in quick succession, KurrentDB will only append one of the events to the stream. + +For example, the following code will only append a single event: + + + +![Duplicate Event](/assets/img/doc-imgs/client/grpc/images/duplicate-event.webp) + +### type + +Each event should be supplied with an event type. This unique string is used to identify the type of event you are saving. + +It is common to see the explicit event code type name used as the type as it makes serialising and de-serialising of the event easy. However, we recommend against this as it couples the storage to the type and will make it more difficult if you need to version the event at a later date. + +### data + +Representation of your event data. It is recommended that you store your events as JSON objects. This allows you to take advantage of all of KurrentDB's functionality, such as projections. That said, you can save events using whatever format suits your workflow. Eventually, the data will be stored as encoded bytes. + +### metadata + +Storing additional information alongside your event that is part of the event itself is standard practice. This can be correlation IDs, timestamps, access information, etc. KurrentDB allows you to store a separate byte array containing this information to keep it separate. + +### isJson + +Simple boolean field to tell KurrentDB if the event is stored as json, true by default. + +## Handling concurrency + +When appending events to a stream, you can supply a *stream state* or *stream revision*. Your client uses this to inform KurrentDB of the state or version you expect the stream to be in when appending an event. If the stream isn't in that state, an exception will be thrown. + +For example, if you try to append the same record twice, expecting both times that the stream doesn't exist, you will get an exception on the second: + + + + + + + +There are three available stream states: +- `Any` +- `NoStream` +- `StreamExists` + +This check can be used to implement optimistic concurrency. When retrieving a stream from KurrentDB, note the current version number. When you save it back, you can determine if somebody else has modified the record in the meantime. + + + +## User credentials + +You can provide user credentials to append the data as follows. This will override the default credentials set on the connection. + + \ No newline at end of file diff --git a/docs/src/content/docs/client/grpc/authentication.mdx b/docs/src/content/docs/client/grpc/authentication.mdx new file mode 100644 index 00000000..5b2ac7de --- /dev/null +++ b/docs/src/content/docs/client/grpc/authentication.mdx @@ -0,0 +1,63 @@ +--- +title: Authentication +order: 7 +--- + +import typescript_client_with_user_certificates_user_certificates from '/src/content/_samples/clients/node/6.2.1/user-certificates.ts?raw'; + +import { Badge, Code, TabItem, Tabs } from '@astrojs/starlight/components'; + + +## Client x.509 certificate + +X.509 certificates are digital certificates that use the X.509 public key infrastructure (PKI) standard to verify the identity of clients and servers. They play a crucial role in establishing a secure connection by providing a way to authenticate identities and establish trust. + +### Prerequisites + +1. KurrentDB 25.0 or greater, or EventStoreDB 24.10. +2. A commercial license with the User Certificates entitlement. +3. A valid x.509 certificate, which can be created using version `1.3` or higher of the [gencert tool](https://github.com/kurrent-io/es-gencert-cli). +4. The server must run in secure mode. See [Security Options](@server/security/protocol-security.md) for more information. +5. [Enable User Certificates plugin on the server](@server/security/user-authentication.md#user-x509-certificates) + +#### Generate user certificates + +The following command uses the [gencert tool](https://github.com/kurrent-io/es-gencert-cli) to generate a user certificate for the user `admin` that will expire in 10 days: + + + +```bash +./es-gencert-cli create-user -username admin -days 10 -ca-certificate ./es-ca/ca.crt -ca-key ./es-ca/ca.key +``` + + +```powershell +.\es-gencert-cli.exe create-user -username admin -days 10 -ca-certificate ./es-ca/ca.crt -ca-key ./es-ca/ca.key +``` + + + +### Connect to KurrentDB using an x.509 certificate + +To connect to KurrentDB using an x.509 certificate, you need to provide the +certificate and the private key to the client. If both username/password and +certificate authentication data are supplied, the client prioritizes user +credentials for authentication. The client will throw an error if the +certificate and the key are not both provided. + +:::tip +Please note that currently, password-protected private key files are not supported. +::: + +The client supports the following parameters: + +| Parameter | Description | +|----------------|--------------------------------------------------------------------------------| +| `userCertFile` | The file containing the X.509 user certificate in PEM format. | +| `userKeyFile` | The file containing the user certificate’s matching private key in PEM format. | + +To authenticate, include these two parameters in your connection string or constructor when initializing the client. + +Check the samples for the following clients: + + \ No newline at end of file diff --git a/docs/src/content/docs/client/grpc/delete-stream.mdx b/docs/src/content/docs/client/grpc/delete-stream.mdx new file mode 100644 index 00000000..a4d31244 --- /dev/null +++ b/docs/src/content/docs/client/grpc/delete-stream.mdx @@ -0,0 +1,30 @@ +--- +title: "Deleting events" +--- + + +In KurrentDB, you can delete events and streams either partially or completely. Settings like $maxAge and $maxCount help control how long events are kept or how many events are stored in a stream, but they won't delete the entire stream. +When you need to fully remove a stream, KurrentDB offers two options: Soft Delete and Hard Delete. + +## Soft delete + +Soft delete in KurrentDB allows you to mark a stream for deletion without completely removing it, so you can still add new events later. While you can do this through the UI, using code is often better for automating the process, +handling many streams at once, or including custom rules. Code is especially helpful for large-scale deletions or when you need to integrate soft deletes into other workflows. + +```javascript +await client.deleteStream(streamName); +``` +:::note +Clicking the delete button in the UI performs a soft delete, +setting the TruncateBefore value to remove all events up to a certain point. +While this marks the events for deletion, actual removal occurs during the next scavenging process. +The stream can still be reopened by appending new events. +::: + +## Hard delete + +Hard delete in KurrentDB permanently removes a stream and its events. While you can use the HTTP API, code is often better for automating the process, managing multiple streams, and ensuring precise control. Code is especially useful when you need to integrate hard delete into larger workflows or apply specific conditions. Note that when a stream is hard deleted, you cannot reuse the stream name, it will raise an exception if you try to append to it again. + +```javascript +await client.tombstoneStream(streamName); +``` \ No newline at end of file diff --git a/docs/src/content/docs/client/grpc/getting-started.mdx b/docs/src/content/docs/client/grpc/getting-started.mdx new file mode 100644 index 00000000..dc1f3374 --- /dev/null +++ b/docs/src/content/docs/client/grpc/getting-started.mdx @@ -0,0 +1,128 @@ +--- +order: 1 +title: "Getting started" + +--- + +import typescript_createClient_get_started from '/src/content/_samples/clients/node/6.2.1/get-started.ts?raw'; +import typescript_createEvent_get_started from '/src/content/_samples/clients/node/6.2.1/get-started.ts?raw'; +import typescript_appendEvents_get_started from '/src/content/_samples/clients/node/6.2.1/get-started.ts?raw'; +import typescript_readStream_get_started from '/src/content/_samples/clients/node/6.2.1/get-started.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + +Get started by connecting your application to KurrentDB. + +## Connecting to KurrentDB + +For your application to start communicating with KurrentDB, you need to instantiate the client and configure it accordingly. Below are instructions for supported SDKs. + +:::tip[Insecure clusters] +All our GRPC clients are secure by default and must be configured to connect to an insecure server via [a connection string](#connection-string) or the client's configuration. +::: + +### Required packages + +Install the client SDK package to your project. + +#### NodeJS + +Install the `@kurrent/kurrentdb-client` package using NPM, Yarn or PNPM: + + + + ```bash + npm install --save @kurrent/kurrentdb-client + ``` + + + ```bash + yarn add @kurrent/kurrentdb-client + ``` + + + ```bash + pnpm add @kurrent/kurrentdb-client + ``` + + + +TypeScript Declarations are included in the package. + +### Connection string + +Each SDK has its own way of configuring the client, but the connection string can always be used. +The KurrentDB connection string supports two schemas: `kurrentdb://` for connecting to a single-node server, and `kurrentdb+discover://` for connecting to a multi-node cluster. The difference between the two schemas is that when using `kurrentdb://`, the client will connect directly to the node; with `kurrentdb+discover://` schema the client will use the gossip protocol to retrieve the cluster information and choose the right node to connect to. +Since version 22.10, ESDB supports gossip on single-node deployments, so `kurrentdb+discover://` schema can be used for connecting to any topology. + +The connection string has the following format: + +``` +kurrentdb+discover://admin:changeit@cluster.dns.name:2113 +``` + +There, `cluster.dns.name` is the name of a DNS `A` record that points to all the cluster nodes. Alternatively, you can list cluster nodes separated by comma instead of the cluster DNS name: + +``` +kurrentdb+discover://admin:changeit@node1.dns.name:2113,node2.dns.name:2113,node3.dns.name:2113 +``` + +There are a number of query parameters that can be used in the connection string to instruct the cluster how and where the connection should be established. All query parameters are optional. + +| Parameter | Accepted values | Default | Description | +|-----------------------|---------------------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------| +| `tls` | `true`, `false` | `true` | Use secure connection, set to `false` when connecting to a non-secure server or cluster. | +| `connectionName` | Any string | None | Connection name | +| `maxDiscoverAttempts` | Number | `10` | Number of attempts to discover the cluster. | +| `discoveryInterval` | Number | `100` | Cluster discovery polling interval in milliseconds. | +| `gossipTimeout` | Number | `5` | Gossip timeout in seconds, when the gossip call times out, it will be retried. | +| `nodePreference` | `leader`, `follower`, `random`, `readOnlyReplica` | `leader` | Preferred node role. When creating a client for write operations, always use `leader`. | +| `tlsVerifyCert` | `true`, `false` | `true` | In secure mode, set to `true` when using an untrusted connection to the node if you don't have the CA file available. Don't use in production. | +| `tlsCaFile` | String, file path | None | Path to the CA file when connecting to a secure cluster with a certificate that's not signed by a trusted CA. | +| `defaultDeadline` | Number | None | Default timeout for client operations, in milliseconds. Most clients allow overriding the deadline per operation. | +| `keepAliveInterval` | Number | `10` | Interval between keep-alive ping calls, in seconds. | +| `keepAliveTimeout` | Number | `10` | Keep-alive ping call timeout, in seconds. | +| `userCertFile` | String, file path | None | User certificate file for X.509 authentication. | +| `userKeyFile` | String, file path | None | Key file for the user certificate used for X.509 authentication. | + +When connecting to an insecure instance, specify `tls=false` parameter. For example, for a node running locally use `kurrentdb://localhost:2113?tls=false`. Note that usernames and passwords aren't provided there because insecure deployments don't support authentication and authorisation. + +### Creating a client + +First, create a client and get it connected to the database. + + + +The client instance can be used as a singleton across the whole application. It doesn't need to open or close the connection. + +### Creating an event + +You can write anything to KurrentDB as events. The client needs a byte array as the event payload. Normally, you'd use a serialized object, and it's up to you to choose the serialization method. + +:::tip[Server-side projections] +User-defined server-side projections require events to be serialized in JSON format. + +We use JSON for serialization in the documentation examples. +::: + +The code snippet below creates an event object instance, serializes it, and adds it as a payload to the `EventData` structure, which the client can then write to the database. + + + +### Appending events + +Each event in the database has its own unique identifier (UUID). The database uses it to ensure idempotent writes, but it only works if you specify the stream revision when appending events to the stream. + +In the snippet below, we append the event to the stream `some-stream`. + + + +Here we are appending events without checking if the stream exists or if the stream version matches the expected event version. See more advanced scenarios in [appending events documentation](./appending-events.md). + +### Reading events + +Finally, we can read events back from the `some-stream` stream. + + + +When you read events from the stream, you get a collection of `ResolvedEvent` structures. The event payload is returned as a byte array and needs to be deserialized. See more advanced scenarios in [reading events documentation](./reading-events.md). diff --git a/docs/src/content/docs/client/grpc/index.mdx b/docs/src/content/docs/client/grpc/index.mdx new file mode 100644 index 00000000..52d98764 --- /dev/null +++ b/docs/src/content/docs/client/grpc/index.mdx @@ -0,0 +1,9 @@ +--- +index: false +breadcrumbExclude: true +title: "Clients" + +--- + + +Learn how to use the KurrentDB client libraries to interact with the database. diff --git a/docs/src/content/docs/client/grpc/observability.mdx b/docs/src/content/docs/client/grpc/observability.mdx new file mode 100644 index 00000000..135a3ded --- /dev/null +++ b/docs/src/content/docs/client/grpc/observability.mdx @@ -0,0 +1,128 @@ +--- +order: 8 +title: "Observability" + +--- + +import typescript_register_instrumentation_opentelemetry from '/src/content/_samples/clients/node/6.2.1/opentelemetry.ts?raw'; +import typescript_setup_exporter_opentelemetry from '/src/content/_samples/clients/node/6.2.1/opentelemetry.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + + +The KurrentDB gRPC clients are designed with observability in mind, offering +support for OpenTelemetry. This integration provides a set of distributed +traces, enabling developers to gain deeper insights into their system. + +:::warning +Currently, OpenTelemetry observability support is not available for all +clients. Moreover, instrumentation is only provided for append and +subscribe operations, which includes both 'Catchup' and 'Persistent' modes. +::: + +You can click on the links below to view the full code for each client: + +- [NodeJS](https://github.com/kurrent-io/KurrentDB-Client-NodeJS/blob/master/packages/test/src/samples/opentelemetry.ts) + +## Required packages + +OpenTelemetry support is included to the KurrentDB Java client by default. For other clients, you need to install the dedicated package to enable OpenTelemetry support. + +### NodeJS + +Install the `@kurrent/opentelemetry` package using your package manager of choice. TypeScript type declarations are included in the package. + + + + ```bash + npm install --save @kurrent/opentelemetry + ``` + + + ```bash + yarn add @kurrent/opentelemetry + ``` + + + ```bash + pnpm add @kurrent/opentelemetry + ``` + + + +## Instrumentation + +To emit trace data, you must first install and use the dedicated package, as instructed in the +[Required Packages](./observability.md#required-packages) section, if provided. This package +includes the necessary instrumentation that needs to be registered with the client. + + + +## Traces + +Traces provide a clear picture of how operations are carried out in a +distributed system, making it easier to maintain and enhance the system over +time. Traces from the clients can be exported to any compatible collector that +supports the OpenTelemetry protocol (OTLP). + +In order for the client to emit traces, you need to need to enable +instrumentation as described in +[Instrumentation](./observability.md#instrumentation). + +For more guidance on setting up and utilizing tracing, refer to the +[OpenTelemetry](https://opentelemetry.io/) documentation. + +An example of a trace is shown below: + +```bash +Activity.TraceId: 8da04787239dbb85c1f9c6fba1b1f0d6 +Activity.SpanId: 4352ec4a66a20b95 +Activity.TraceFlags: Recorded +Activity.ActivitySourceName: kurrentdb +Activity.DisplayName: streams.append +Activity.Kind: Client +Activity.StartTime: 2024-05-29T06:50:41.2519016Z +Activity.Duration: 00:00:00.1500707 +Activity.Tags: + db.kurrentdb.stream: d7caa2a5-1e19-4108-9541-58d5fba02d42 + server.address: localhost + server.port: 2113 + db.system: kurrentdb + db.operation: streams.append +StatusCode: Ok +Resource associated with Activity: + service.name: sample + service.instance.id: 7316ef20-c354-4e64-97da-c1b99c2c28b0 + telemetry.sdk.name: opentelemetry + telemetry.sdk.language: dotnet + telemetry.sdk.version: 1.8.1 +``` + +In this case, the trace is for an append operation on a stream. The trace +includes the trace ID, span ID, trace flags, activity source name, display name, +kind, start time, duration, tags, status code, and resource associated with the +activity. + +:::note +The structure of the trace may vary depending on the client and the operation +being performed but will generally include the same information. +::: + +## Exporting traces + +You can set up various exporters to send traces to different destinations. +Additionally, you have the option to export these traces to a collector of your +choice, such as [Jaeger](https://www.jaegertracing.io/) or [Seq](https://datalust.co/seq). + +For instance, if you choose to use Jaeger as your backend of choice, you can +view your traces in the Jaeger UI, which provides a powerful interface for +querying and visualizing your trace data. + +The code snippets below demonstrate how to set up one or more exporters for each +client: + + + +For more details on configuring exporters for specific programming languages, +refer to the [OpenTelemetry](https://opentelemetry.io/docs/languages/) +documentation. diff --git a/docs/src/content/docs/client/grpc/persistent-subscriptions.mdx b/docs/src/content/docs/client/grpc/persistent-subscriptions.mdx new file mode 100644 index 00000000..753db01a --- /dev/null +++ b/docs/src/content/docs/client/grpc/persistent-subscriptions.mdx @@ -0,0 +1,176 @@ +--- +order: 5 +title: "Persistent subscriptions" + +--- + +import typescript_create_persistent_subscription_to_stream_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; +import typescript_create_persistent_subscription_to_all_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; +import typescript_subscribe_to_persistent_subscription_to_stream_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; +import typescript_subscribe_to_persistent_subscription_to_all_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; +import typescript_subscribe_to_persistent_subscription_with_manual_acks_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; +import typescript_update_persistent_subscription_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; +import typescript_delete_persistent_subscription_persistent_subscriptions from '/src/content/_samples/clients/node/6.2.1/persistent-subscriptions.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + + +Persistent subscriptions are similar to catch-up subscriptions, but there are two key differences: +- The subscription checkpoint is maintained by the server. It means that when your client reconnects to the persistent subscription, it will automatically resume from the last known position. +- It's possible to connect more than one event consumer to the same persistent subscription. In that case, the server will load-balance the consumers, depending on the defined strategy, and distribute the events to them. + +Because of those, persistent subscriptions are defined as subscription groups that are defined and maintained by the server. Consumer then connect to a particular subscription group, and the server starts sending event to the consumer. + +You can read more about persistent subscriptions in the [server documentation](@server/features/persistent-subscriptions.md). + +## Creating a subscription group + +The first step of dealing with a persistent subscription is to create a subscription group. You will receive an error if you attempt to create a subscription group multiple times. You must have admin permissions to create a persistent subscription group. + +### Subscribing to one stream + +The following sample shows how to create a subscription group for a persistent subscription where you want to receive events from a specific stream. It could be a normal stream, or a stream of links (like `$ce` category stream). + + + + +| Parameter | Description | +|:--------------|:----------------------------------------------------| +| `stream` | The stream the persistent subscription is on. | +| `groupName` | The name of the subscription group to create. | +| `settings` | The settings to use when creating the subscription. | +| `credentials` | The user credentials to use for this operation. | + +### Subscribing to $all + +The ability to subscribe to `$all` was introduced in EventStoreDB **21.10**. Persistent subscriptions to `$all` also support [filtering](subscriptions.md#server-side-filtering). + +You can create a subscription group on $all much the same way you would create a subscription group on a stream: + + + + + + + +## Connecting a consumer + +Once you have created a subscription group, clients can connect to it. A subscription in your application should only have the connection in your code, you should assume that the subscription already exists. + +The most important parameter to pass when connecting is the buffer size. This represents how many outstanding messages the server should allow this client. If this number is too small, your subscription will spend much of its time idle as it waits for an acknowledgment to come back from the client. If it's too big, you waste resources and can start causing time out messages depending on the speed of your processing. + +### Connecting to one stream + +The code below shows how to connect to an existing subscription group for a specific stream: + + + +| Parameter | Description | +|:----------------------|:---------------------------------------------------------------------------------------------| +| `stream` | The stream the persistent subscription is on. | +| `groupName` | The name of the subscription group to subscribe to. | +| `eventAppeared` | The action to call when an event arrives over the subscription. | +| `subscriptionDropped` | The action to call if the subscription is dropped. | +| `credentials` | The user credentials to use for this operation. | +| `bufferSize` | The number of in-flight messages this client is allowed. **Default: 10** | +| `autoAck` | Whether to automatically acknowledge messages after eventAppeared returns. **Default: true** | + +:::warning +The `autoAck` parameter will be deprecated in the next client release. You'll need to explicitly [manage acknowledgements](#acknowledgements). +::: + +### Connecting to $all + +The code below shows how to connect to an existing subscription group for `$all`: + + + +The `SubscribeToAllAsync` method is identical to the `SubscribeToStreamAsync` method, except that you don't need to specify a stream name. + +## Acknowledgements + +Clients must acknowledge (or not acknowledge) messages in the competing consumer model. + +If processing is successful, you must send an Ack (acknowledge) to the server to let it know that the message has been handled. If processing fails for some reason, then you can Nack (not acknowledge) the message and tell the server how to handle the failure. + + + +The _Nack event action_ describes what the server should do with the message: + +| Action | Description | +|:----------|:---------------------------------------------------------------------| +| `Unknown` | The client does not know what action to take. Let the server decide. | +| `Park` | Park the message and do not resend. Put it on poison queue. | +| `Retry` | Explicitly retry the message. | +| `Skip` | Skip this message do not resend and do not put in poison queue. | + +## Consumer strategies + +When creating a persistent subscription, you can choose between a number of consumer strategies. + +### RoundRobin (default) + +Distributes events to all clients evenly. If the client `bufferSize` is reached, the client won't receive more events until it acknowledges or not acknowledges events in its buffer. + +This strategy provides equal load balancing between all consumers in the group. + +### DispatchToSingle + +Distributes events to a single client until the `bufferSize` is reached. After that, the next client is selected in a round-robin style, and the process repeats. + +This option can be seen as a fall-back scenario for high availability, when a single consumer processes all the events until it reaches its maximum capacity. When that happens, another consumer takes the load to free up the main consumer resources. + +### Pinned + +For use with an indexing projection such as the system `$by_category` projection. + +KurrentDB inspects the event for its source stream id, hashing the id to one of 1024 buckets assigned to individual clients. When a client disconnects, its buckets are assigned to other clients. When a client connects, it is assigned some existing buckets. This naively attempts to maintain a balanced workload. + +The main aim of this strategy is to decrease the likelihood of concurrency and ordering issues while maintaining load balancing. This is **not a guarantee**, and you should handle the usual ordering and concurrency issues. + +## Updating a subscription group + +You can edit the settings of an existing subscription group while it is running, you don't need to delete and recreate it to change settings. When you update the subscription group, it resets itself internally, dropping the connections and having them reconnect. You must have admin permissions to update a persistent subscription group. + + + +| Parameter | Description | +|:--------------|:----------------------------------------------------| +| `stream` | The stream the persistent subscription is on. | +| `groupName` | The name of the subscription group to update. | +| `settings` | The settings to use when creating the subscription. | +| `credentials` | The user credentials to use for this operation. | + +## Persistent subscription settings + +Both the `Create` and `Update` methods take some settings for configuring the persistent subscription. + +The following table shows the configuration options you can set on a persistent subscription. + +| Option | Description | Default | +|:------------------------|:----------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------| +| `ResolveLinkTos` | Whether the subscription should resolve link events to their linked events. | `false` | +| `StartFrom` | The exclusive position in the stream or transaction file the subscription should start from. | `null` (start from the end of the stream) | +| `ExtraStatistics` | Whether to track latency statistics on this subscription. | `false` | +| `MessageTimeout` | The amount of time after which to consider a message as timed out and retried. | `30` (seconds) | +| `MaxRetryCount` | The maximum number of retries (due to timeout) before a message is considered to be parked. | `10` | +| `LiveBufferSize` | The size of the buffer (in-memory) listening to live messages as they happen before paging occurs. | `500` | +| `ReadBatchSize` | The number of events read at a time when paging through history. | `20` | +| `HistoryBufferSize` | The number of events to cache when paging through history. | `500` | +| `CheckPointAfter` | The amount of time to try to checkpoint after. | `2` seconds | +| `MinCheckPointCount` | The minimum number of messages to process before a checkpoint may be written. | `10` | +| `MaxCheckPointCount` | The maximum number of messages not checkpointed before forcing a checkpoint. | `1000` | +| `MaxSubscriberCount` | The maximum number of subscribers allowed. | `0` (unbounded) | +| `NamedConsumerStrategy` | The strategy to use for distributing events to client consumers. See the [consumer strategies](#consumer-strategies) in this doc. | `RoundRobin` | + +## Deleting a subscription group + +Remove a subscription group with the delete operation. Like the creation of groups, you rarely do this in your runtime code and is undertaken by an administrator running a script. + + + +| Parameter | Description | +|:--------------|:-----------------------------------------------| +| `stream` | The stream the persistent subscription is on. | +| `groupName` | The name of the subscription group to delete. | +| `credentials` | The user credentials to use for this operation | diff --git a/docs/src/content/docs/client/grpc/projections.mdx b/docs/src/content/docs/client/grpc/projections.mdx new file mode 100644 index 00000000..df78a448 --- /dev/null +++ b/docs/src/content/docs/client/grpc/projections.mdx @@ -0,0 +1,232 @@ +--- +title: "Untitled" +--- + +import typescript_createClient_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_CreateContinuous_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_CreateContinuous_Conflict_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_RestartSubSystem_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Enable_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_EnableNotFound_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Disable_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_DisableNotFound_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Delete_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_DeleteNotFound_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Abort_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Abort_NotFound_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Reset_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Reset_NotFound_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Update_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_Update_NotFound_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_ListAll_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_ListContinuous_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_GetStatus_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_GetState_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; +import typescript_GetResult_projection_management from '/src/content/_samples/clients/node/6.2.1/projection-management.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + + +--- +order: 6 +title: Projections +--- + +# Projection management + +The various gRPC client APIs include dedicated clients that allow you to manage projections. + +For a detailed explanation of projections, see the [server documentation](@server/features/projections/README.md). + +You can find the full sample code from this documentation page in the respective [clients repositories](https://github.com/kurrent-io/?q=client). + +## Required packages + +Install the client SDK package to your project. + +### NodeJS + +Add `@kurrent/kurrentdb-client` to your project using Yarn, NPM, or pnpm. + +TypeScript type declarations are included in the package. + + + + ```bash + npm install --save @kurrent/kurrentdb-client + ``` + + + ```bash + yarn add @kurrent/kurrentdb-client + ``` + + + ```bash + pnpm add @kurrent/kurrentdb-client + ``` + + + +## Creating a client + +Projection management operations are exposed through a dedicated client. + + + +## Create a projection + +Creates a projection that runs until the last event in the store, and then continues processing new events as they are appended to the store. The query parameter contains the JavaScript you want created as a projection. +Projections have explicit names, and you can enable or disable them via this name. + + + +Trying to create projections with the same name will result in an error: + + + +## Restart the subsystem + +It is possible to restart the entire projection subsystem using the projections management client API. The user must be in the `$ops` or `$admin` group to perform this operation. + + + +## Enable a projection + +Enables an existing projection by name. +Once enabled, the projection will start to process events even after restarting the server or the projection subsystem. +You must have access to a projection to enable it, see the [ACL documentation](@server/security/user-authorization.md). + + + +You can only enable an existing projection. When you try to enable a non-existing projection, you'll get an error: + + + +## Disable a projection + +Disables a projection, this will save the projection checkpoint. +Once disabled, the projection will not process events even after restarting the server or the projection subsystem. +You must have access to a projection to disable it, see the [ACL documentation](@server/security/user-authorization.md). + + + +You can only disable an existing projection. When you try to disable a non-existing projection, you'll get an error: + + + +## Delete a projection + +Deletes an existing projection. You must disable the projection before deleting it, running projections cannot be deleted. Deleting a projection includes deleting the checkpoint and the emitted streams. + + + +You can only delete an existing projection. When you try to delete a non-existing projection, you'll get an error: + + + +## Abort a projection + +Aborts a projection, this will not save the projection's checkpoint. + + + +You can only abort an existing projection. When you try to abort a non-existing projection, you'll get an error: + + + +## Reset a projection + +Resets a projection, which causes deleting the projection checkpoint. This will force the projection to start afresh and re-emit events. Streams that are written to from the projection will also be soft-deleted. + + + +Resetting a projection that does not exist will result in an error. + + + +## Update a projection + +Updates a projection with a given name. The query parameter contains the new JavaScript. Updating system projections using this operation is not supported at the moment. + + + +You can only update an existing projection. When you try to update a non-existing projection, you'll get an error: + + + +## List all projections + +Returns a list of all projections, user defined & system projections. +See the [projection details](#projection-details) section for an explanation of the returned values. + + + +## List continuous projections + +Returns a list of all continuous projections. +See the [projection details](#projection-details) section for an explanation of the returned values. + + + +## Get status + +Gets the status of a named projection. +See the [projection details](#projection-details) section for an explanation of the returned values. + + + +## Get state + +Retrieves the state of a projection. + + + +## Get result + +Retrieves the result of the named projection and partition. + + + +## Projection Details + +[List all](#list-all-projections), [list continuous](#list-continuous-projections) and [get status](#get-status) all return the details and statistics of projections + +| Field | Description | +|--------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `Name`, `EffectiveName` | The name of the projection | +| `Status` | A human readable string of the current statuses of the projection (see below) | +| `StateReason` | A human readable string explaining the reason of the current projection state | +| `CheckpointStatus` | A human readable string explaining the current operation performed on the checkpoint : `requested`, `writing` | +| `Mode` | `Continuous`, `OneTime` , `Transient` | +| `CoreProcessingTime` | The total time, in ms, the projection took to handle events since the last restart | +| `Progress` | The progress, in %, indicates how far this projection has processed event, in case of a restart this could be -1% or some number. It will be updated as soon as a new event is appended and processed | +| `WritesInProgress` | The number of write requests to emitted streams currently in progress, these writes can be batches of events | +| `ReadsInProgress` | The number of read requests currently in progress | +| `PartitionsCached` | The number of cached projection partitions | +| `Position` | The Position of the last processed event | +| `LastCheckpoint` | The Position of the last checkpoint of this projection | +| `EventsProcessedAfterRestart` | The number of events processed since the last restart of this projection | +| `BufferedEvents` | The number of events in the projection read buffer | +| `WritePendingEventsBeforeCheckpoint` | The number of events waiting to be appended to emitted streams before the pending checkpoint can be written | +| `WritePendingEventsAfterCheckpoint` | The number of events to be appended to emitted streams since the last checkpoint | +| `Version` | This is used internally, the version is increased when the projection is edited or reset | +| `Epoch` | This is used internally, the epoch is increased when the projection is reset | + +The `Status` string is a combination of the following values. +The first 3 are the most common one, as the other one are transient values while the projection is initialised or stopped + +| Value | Description | +|--------------------|-------------------------------------------------------------------------------------------------------------------------| +| Running | The projection is running and processing events | +| Stopped | The projection is stopped and is no longer processing new events | +| Faulted | An error occurred in the projection, `StateReason` will give the fault details, the projection is not processing events | +| Initial | This is the initial state, before the projection is fully initialised | +| Suspended | The projection is suspended and will not process events, this happens while stopping the projection | +| LoadStateRequested | The state of the projection is being retrieved, this happens while the projection is starting | +| StateLoaded | The state of the projection is loaded, this happens while the projection is starting | +| Subscribed | The projection has successfully subscribed to its readers, this happens while the projection is starting | +| FaultedStopping | This happens before the projection is stopped due to an error in the projection | +| Stopping | The projection is being stopped | +| CompletingPhase | This happens while the projection is stopping | +| PhaseCompleted | This happens while the projection is stopping | diff --git a/docs/src/content/docs/client/grpc/reading-events.mdx b/docs/src/content/docs/client/grpc/reading-events.mdx new file mode 100644 index 00000000..2b643ec0 --- /dev/null +++ b/docs/src/content/docs/client/grpc/reading-events.mdx @@ -0,0 +1,146 @@ +--- +order: 3 +title: "Reading events" + +--- + +import typescript_read_from_stream_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_iterate_stream_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_overriding_user_credentials_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_read_from_stream_position_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_reading_backwards_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_checking_for_stream_presence_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_read_from_all_stream_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_read_from_all_stream_iterate_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_read_from_all_stream_resolving_link_Tos_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_read_all_overriding_user_credentials_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_read_from_all_stream_backwards_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; +import typescript_ignore_system_events_reading_events from '/src/content/_samples/clients/node/6.2.1/reading-events.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + + +There are two options for reading events from KurrentDB. You can either: + 1. Read from an individual stream, or + 2. Read from the `$all` stream, which will return all events in the store. + +Each event in KurrentDB belongs to an individual stream. When reading events, pick the name of the stream from which you want to read the events and choose whether to read the stream forwards or backwards. + +All events have a `StreamPosition` and a `Position`. `StreamPosition` is a *big int* (unsigned 64-bit integer) and represents the place of the event in the stream. `Position` is the event's logical position, and is represented by `CommitPosition` and a `PreparePosition`. Note that when reading events you will supply a different "position" depending on whether you are reading from an individual stream or the `$all` stream. + +:::tip +Check [connecting to KurrentDB instructions](getting-started.md#required-packages) to learn how to configure and use the client SDK. +::: + +## Reading from a stream + +You can read all the events or a sample of the events from individual streams, starting from any position in the stream, and can read either forward or backward. It is only possible to read events from a single stream at a time. You can read events from the global event log, which spans across streams. Learn more about this process in the [Read from `$all`](#reading-from-the-all-stream) section below. + +### Reading forwards + +The simplest way to read a stream forwards is to supply a stream name, read direction, and revision from which to start. The revision can either be a *stream position* `Start` or a *big int* (unsigned 64-bit integer): + + + +This will return an enumerable that can be iterated on: + + + +There are a number of additional arguments you can provide when reading a stream, listed below. + +#### maxCount + +Passing in the max count will limit the number of events returned. + +#### resolveLinkTos + +When using projections to create new events, you can set whether the generated events are pointers to existing events. Setting this value to `true` tells KurrentDB to return the event as well as the event linking to it. + +#### configureOperationOptions + +You can use the `configureOperationOptions` argument to provide a function that will customise settings for each operation. + +#### userCredentials + +The `userCredentials` argument is optional. It is used to override the default credentials specified when creating the client instance. + + + +### Reading from a revision + +Instead of providing the `StreamPosition` you can also provide a specific stream revision as a *big int* (unsigned 64-bit integer). + + + +### Reading backwards + +In addition to reading a stream forwards, streams can be read backwards. To read all the events backwards, set the *stream position* to the end: + + + +:::tip +Read one event backwards to find the last position in the stream. +::: + +### Checking if the stream exists + +Reading a stream returns a `ReadStreamResult`, which contains a property `ReadState`. This property can have the value `StreamNotFound` or `Ok`. + +It is important to check the value of this field before attempting to iterate an empty stream, as it will throw an exception. + +For example: + + + +## Reading from the $all stream + +Reading from the `$all` stream is similar to reading from an individual stream, but please note there are differences. One significant difference is the need to provide admin user account credentials to read from the `$all` stream. Additionally, you need to provide a transaction log position instead of a stream revision when reading from the `$all` stream. + +### Reading forwards + +The simplest way to read the `$all` stream forwards is to supply a read direction and the transaction log position from which you want to start. The transaction log postion can either be a *stream position* `Start` or a *big int* (unsigned 64-bit integer): + + + +You can iterate asynchronously through the result: + + + +There are a number of additional arguments you can provide when reading the `$all` stream. + +#### maxCount + +Passing in the max count allows you to limit the number of events that returned. + +#### resolveLinkTos + +When using projections to create new events you can set whether the generated events are pointers to existing events. Setting this value to true will tell KurrentDB to return the event as well as the event linking to it. + + + +#### configureOperationOptions + +This argument is generic setting class for all operations that can be set on all operations executed against KurrentDB. + +#### userCredentials +The credentials used to read the data can be used by the subscription as follows. This will override the default credentials set on the connection. + + + +### Reading backwards + +In addition to reading the `$all` stream forwards, it can be read backwards. To read all the events backwards, set the *position* to the end: + + + +:::tip +Read one event backwards to find the last position in the `$all` stream. +::: + +### Handling system events + +KurrentDB will also return system events when reading from the `$all` stream. In most cases you can ignore these events. + +All system events begin with `$` or `$$` and can be easily ignored by checking the `EventType` property. + + diff --git a/docs/src/content/docs/client/grpc/sidebar.json b/docs/src/content/docs/client/grpc/sidebar.json new file mode 100644 index 00000000..e4a611d6 --- /dev/null +++ b/docs/src/content/docs/client/grpc/sidebar.json @@ -0,0 +1,42 @@ +[ + { + "label": "Overview", + "link": "/client\\grpc" + }, + { + "label": "Appending Events", + "link": "/client\\grpc/appending-events" + }, + { + "label": "Authentication", + "link": "/client\\grpc/authentication" + }, + { + "label": "Delete Stream", + "link": "/client\\grpc/delete-stream" + }, + { + "label": "Getting Started", + "link": "/client\\grpc/getting-started" + }, + { + "label": "Observability", + "link": "/client\\grpc/observability" + }, + { + "label": "Persistent Subscriptions", + "link": "/client\\grpc/persistent-subscriptions" + }, + { + "label": "Projections", + "link": "/client\\grpc/projections" + }, + { + "label": "Reading Events", + "link": "/client\\grpc/reading-events" + }, + { + "label": "Subscriptions", + "link": "/client\\grpc/subscriptions" + } +] \ No newline at end of file diff --git a/docs/src/content/docs/client/grpc/subscriptions.mdx b/docs/src/content/docs/client/grpc/subscriptions.mdx new file mode 100644 index 00000000..0421b088 --- /dev/null +++ b/docs/src/content/docs/client/grpc/subscriptions.mdx @@ -0,0 +1,252 @@ +--- +order: 4 +title: "Catch-up subscriptions" + +--- + +import typescript_subscribe_to_stream_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_all_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_stream_from_position_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_all_from_position_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_stream_live_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_all_live_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_stream_resolving_linktos_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_stream_subscription_dropped_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_subscribe_to_all_subscription_dropped_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_overriding_user_credentials_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_stream_prefix_filtered_subscription_subscribing_to_streams from '/src/content/_samples/clients/node/6.2.1/subscribing-to-streams.ts?raw'; +import typescript_exclude_system_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; +import typescript_event_type_prefix_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; +import typescript_event_type_regex_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; +import typescript_stream_prefix_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; +import typescript_stream_regex_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; +import typescript_checkpoint_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; +import typescript_checkpoint_with_interval_server_side_filtering from '/src/content/_samples/clients/node/6.2.1/server-side-filtering.ts?raw'; + +import { Code, TabItem, Tabs } from '@astrojs/starlight/components'; + + +Subscriptions allow you to subscribe to a stream and receive notifications about new events added to the stream. + +You provide an event handler and an optional starting point to the subscription. The handler is called for each event from the starting point onward. + +If events already exist, the handler will be called for each event one by one until it reaches the end of the stream. The server will then notify the handler whenever a new event appears. + +:::tip +Check the [Getting Started](getting-started.md) guide to learn how to configure and use the client SDK. +::: + +## Subscribing from the start + +If you need to process all the events in the store, including historical events, you'll need to subscribe from the beginning. You can either subscribe to receive events from a single stream or subscribe to `$all` if you need to process all events in the database. + +### Subscribing to a stream + +The simplest stream subscription looks like the following : + + + +The provided handler will be called for every event in the stream. + +When you subscribe to a stream with link events, for example the `$ce` category stream, you need to set `resolveLinkTos` to `true`. Read more about it [below](#resolving-link-to-s). + +### Subscribing to `$all` + +Subscribing to `$all` is similar to subscribing to a single stream. The handler will be called for every event appended after the starting position. + + + +## Subscribing from a specific position + +The previous examples subscribed to the stream from the beginning. That subscription invoked the handler for every event in the stream before waiting for new events. + +Both stream and $all subscriptions accept a starting position if you want to read from a specific point onward. If events already exist at the position you subscribe to, they will be read on the server side and sent to the subscription. + +Once caught up, the server will push any new events received on the streams to the client. There is no difference between catching up and live on the client side. + +:::warning +The positions provided to the subscriptions are exclusive. You will only receive the next event after the subscribed position. +::: + +### Subscribing to a stream + +To subscribe to a stream from a specific position, you must provide a *stream position*. This can be `Start`, `End` or a *big int* (unsigned 64 bit integer) position. + +The following subscribes to the stream `some-stream` at position `20`, this means that events `21` and onward will be handled: + + + +### Subscribing to $all + +Subscribing to the `$all` stream is similar to subscribing to a regular stream. The difference is how to specify the starting position. For the `$all` stream, provide a `Position` structure that consists of two big integers: the prepare and commit positions. Use `Start`, `End`, or create a `Position` from specific commit and prepare values. + +The corresponding `$all` subscription will subscribe from the event after the one at commit position `1056` and prepare position `1056`. + +Please note that this position will need to be a legitimate position in `$all`. + + + +## Subscribing to a stream for live updates + +You can subscribe to a stream to get live updates by subscribing to the end of the stream: + + + +And the same works with `$all` : + + + +This will not read through the history of the stream but will notify the handler when a new event appears in the respective stream. + +Keep in mind that when you subscribe to a stream from a specific position, as described [above](#subscribing-from-a-specific-position), you will also get live updates after your subscription catches up (processes all the historical events). + +## Resolving link-to's + +Link-to events point to events in other streams in KurrentDB. These are generally created by projections such as the `$by_event_type` projection which links events of the same event type into the same stream. This makes it easier to look up all events of a specific type. + +:::tip +[Filtered subscriptions](subscriptions.md#server-side-filtering) make it easier and faster to subscribe to all events of a specific type or matching a prefix. +::: + +When reading a stream you can specify whether to resolve link-to's. By default, link-to events are not resolved. You can change this behaviour by setting the `resolveLinkTos` parameter to `true`: + + + +## Dropped subscriptions + +When a subscription stops or experiences an error, it will be dropped. The subscription provides a `subscriptionDropped` callback, which will get called when the subscription breaks. + +The `subscriptionDropped` callback allows you to inspect the reason why the subscription dropped, as well as any exceptions that occurred. + +The possible reasons for a subscription to drop are: + +| Reason | Why it might happen | +|:------------------|:---------------------------------------------------------------------------------------------------------------------| +| `Disposed` | The client canceled or disposed of the subscription. | +| `SubscriberError` | An error occurred while handling an event in the subscription handler. | +| `ServerError` | An error occurred on the server, and the server closed the subscription. Check the server logs for more information. | + +Bear in mind that a subscription can also drop because it is slow. The server tried to push all the live events to the subscription when it is in the live processing mode. If the subscription gets the reading buffer overflow and won't be able to acknowledge the buffer, it will break. + +### Handling subscription drops + +An application, which hosts the subscription, can go offline for some time for different reasons. It could be a crash, infrastructure failure, or a new version deployment. As you rarely would want to reprocess all the events again, you'd need to store the current position of the subscription somewhere, and then use it to restore the subscription from the point where it dropped off: + + + +When subscribed to `$all` you want to keep the event's position in the `$all` stream. As mentioned previously, the `$all` stream position consists of two big integers (prepare and commit positions), not one: + + + +## User credentials + +The user creating a subscription must have read access to the stream it's subscribing to, and only admin users may subscribe to `$all` or create filtered subscriptions. + +The code below shows how you can provide user credentials for a subscription. When you specify subscription credentials explicitly, it will override the default credentials set for the client. If you don't specify any credentials, the client will use the credentials specified for the client, if you specified those. + + + +## Server-side filtering + +KurrentDB allows you to filter the events whilst subscribing to the `$all` stream to only receive the events you care about. + +You can filter by event type or stream name using a regular expression or a prefix. Server-side filtering is currently only available on the `$all` stream. + +:::tip +Server-side filtering was introduced as a simpler alternative to projections. You should consider filtering before creating a projection to include the events you care about. +::: + +A simple stream prefix filter looks like this: + + + +The filtering API is described more in-depth in the [filtering section](subscriptions.md#server-side-filtering). + +### Filtering out system events + +There are events in KurrentDB called system events. These are prefixed with a `$` and under most circumstances you won't care about these. They can be filtered out by passing in a `SubscriptionFilterOptions` when subscribing to the `$all` stream. + + + +:::tip +`$stats` events are no longer stored in KurrentDB by default so there won't be as many `$` events as before. +::: + +### Filtering by event type + +If you only want to subscribe to events of a given type, there are two options. You can either use a regular expression or a prefix. + +#### Filtering by prefix + +If you want to filter by prefix, pass in a `SubscriptionFilterOptions` to the subscription with an `EventTypeFilter.Prefix`. + + + +This will only subscribe to events with a type that begin with `customer-`. + +#### Filtering by regular expression + +It might be advantageous to provide a regular expression when you want to subscribe to multiple event types. + + + +This will subscribe to any event that begins with `user` or `company`. + +### Filtering by stream name + +To subscribe to a stream by name, choose either a regular expression or a prefix. + +#### Filtering by prefix + +If you want to filter by prefix, pass in a `SubscriptionFilterOptions` to the subscription with an `StreamFilter.Prefix`. + + + +This will only subscribe to all streams with a name that begins with `user-`. + +#### Filtering by regular expression + +To subscribe to multiple streams, use a regular expression. + + + +This will subscribe to any stream with a name that begins with `account` or `savings`. + +## Checkpointing + +When a catch-up subscription is used to process an `$all` stream containing many events, the last thing you want is for your application to crash midway, forcing you to restart from the beginning. + +### What is a checkpoint? + +A checkpoint is the position of an event in the `$all` stream to which your application has processed. By saving this position to a persistent store (e.g., a database), it allows your catch-up subscription to: +- Recover from crashes by reading the checkpoint and resuming from that position +- Avoid reprocessing all events from the start + +To create a checkpoint, store the event's commit or prepare position. + +:::warning +If your database contains events created by the legacy TCP client using the [transaction feature](https://docs.kurrent.io/clients/tcp/dotnet/21.2/appending.html#transactions), you should store both the commit and prepare positions together as your checkpoint. +::: + +### Updating checkpoints at regular intervals +The client SDK provides a way to notify your application after processing a configurable number of events. This allows you to periodically save a checkpoint at regular intervals. + + + +By default, the checkpoint notification is sent after every 32 non-system events processed from $all. + +### Configuring the checkpoint interval +You can adjust the checkpoint interval to change how often the client is notified. + + + +By configuring this parameter, you can balance between reducing checkpoint overhead and ensuring quick recovery in case of a failure. + +:::info +The checkpoint interval parameter configures the database to notify the client after `n` * 32 number of events where `n` is defined by the parameter. + +For example: +- If `n` = 1, a checkpoint notification is sent every 32 events. +- If `n` = 2, the notification is sent every 64 events. +- If `n` = 3, it is sent every 96 events, and so on. +::: diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx new file mode 100644 index 00000000..124da32d --- /dev/null +++ b/docs/src/content/docs/index.mdx @@ -0,0 +1,30 @@ +--- +title: Kurrent docs +description: Get started building your docs site with Starlight. +template: splash +hero: + tagline: This is the small engine for the NodeJS docs on Astro Starlight. + image: + file: ../../assets/img/logo-black.svg + actions: + - text: Start here + link: /client/grpc/ + icon: right-arrow +--- + +import { Card, CardGrid } from '@astrojs/starlight/components'; + + +## Next steps + + + + Add Markdown or MDX files to `src/content/docs` to create new pages. + + + Edit the `sidebar` in `sidebar.json`. + + + Learn more in [the Starlight Docs](https://starlight.astro.build/). Or ask in the `#documentation` channel. + + diff --git a/docs/src/utils/sidebar.ts b/docs/src/utils/sidebar.ts new file mode 100644 index 00000000..1d652371 --- /dev/null +++ b/docs/src/utils/sidebar.ts @@ -0,0 +1,396 @@ +// src/utils/sidebar.ts +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export interface SidebarItem { + label: string; + link?: string; + items?: SidebarItem[]; + autogenerate?: { directory: string }; + collapsed?: boolean; +} + +export interface VersionInfo { + version: string; + label: string; + urlPath: string; +} + +// Parse version string to comparable array +function parseVersion(version: string): number[] { + // Remove 'v' prefix if present + const cleanVersion = version.replace(/^v/, ''); + return cleanVersion.split('.').map(part => parseInt(part, 10) || 0); +} + +// Compare two version arrays using semver logic +function compareVersions(a: number[], b: number[]): number { + const maxLength = Math.max(a.length, b.length); + + for (let i = 0; i < maxLength; i++) { + const aPart = a[i] || 0; + const bPart = b[i] || 0; + + if (aPart > bPart) return 1; + if (aPart < bPart) return -1; + } + + return 0; +} + +// Find the latest version from an array of version strings +function findLatestVersion(versions: string[]): string | null { + if (versions.length === 0) return null; + + let latestVersion = versions[0]; + let latestParsed = parseVersion(latestVersion); + + for (let i = 1; i < versions.length; i++) { + const currentParsed = parseVersion(versions[i]); + if (compareVersions(currentParsed, latestParsed) > 0) { + latestVersion = versions[i]; + latestParsed = currentParsed; + } + } + + return latestVersion; +} + +// Format label from file/folder name +export function formatLabel(name: string): string { + // Remove file extension + const withoutExt = name.replace(/\.(md|mdx)$/, ''); + + // Replace dashes and underscores with spaces + const withSpaces = withoutExt.replace(/[-_]/g, ' '); + + // Capitalize first letter of each word + return withSpaces + .split(' ') + .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(' '); +} + +// Get the sidebar file path for a given content path +export function getSidebarPath(contentPath: string): string | null { + const normalizedPath = contentPath.replace(/\\/g, '/'); + const docsRoot = path.join(process.cwd(), 'src', 'content', 'docs'); + + // Split the path to analyze structure + const pathParts = normalizedPath.split('/').filter(Boolean); + + // Try to find sidebar.json by walking up the directory tree + let currentPath = path.join(docsRoot, ...pathParts); + + while (currentPath.startsWith(docsRoot) && currentPath !== docsRoot) { + const sidebarPath = path.join(currentPath, 'sidebar.json'); + if (fs.existsSync(sidebarPath)) { + return sidebarPath; + } + currentPath = path.dirname(currentPath); + } + + return null; +} + +// Load sidebar from JSON file +export function loadSidebarFromFile(filePath: string): SidebarItem[] | null { + try { + const content = fs.readFileSync(filePath, 'utf-8'); + return JSON.parse(content); + } catch (error) { + console.error(`Error loading sidebar from ${filePath}:`, error); + return null; + } +} + +// Auto-generate sidebar from directory structure +export function generateSidebarFromDirectory(dirPath: string, basePath: string = ''): SidebarItem[] { + const items: SidebarItem[] = []; + + try { + const entries = fs.readdirSync(dirPath, { withFileTypes: true }); + + // Sort entries: directories first, then files + entries.sort((a, b) => { + if (a.isDirectory() && !b.isDirectory()) return -1; + if (!a.isDirectory() && b.isDirectory()) return 1; + return a.name.localeCompare(b.name); + }); + + for (const entry of entries) { + // Skip hidden files, images, and non-content files + if (entry.name.startsWith('.') || + entry.name === 'sidebar.json' || + /\.(png|jpg|jpeg|gif|svg|webp)$/i.test(entry.name)) { + continue; + } + + const fullPath = path.join(dirPath, entry.name); + const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name; + + if (entry.isDirectory()) { + // Check if directory has content + const subItems = generateSidebarFromDirectory(fullPath, relativePath); + if (subItems.length > 0) { + items.push({ + label: formatLabel(entry.name), + items: subItems, + collapsed: true + }); + } + } else if (/\.(md|mdx)$/i.test(entry.name)) { + // Skip index files as they're usually the parent page + if (entry.name.toLowerCase() === 'index.md' || entry.name.toLowerCase() === 'index.mdx') { + continue; + } + + // Generate the link path - ensure forward slashes + const linkPath = `/${relativePath.replace(/\.(md|mdx)$/, '').toLowerCase()}`.replace(/\\/g, '/'); + + items.push({ + label: formatLabel(entry.name), + link: linkPath + }); + } + } + } catch (error) { + console.error(`Error generating sidebar for ${dirPath}:`, error); + } + + return items; +} + +// Extract version information from path +export function extractVersionInfo(contentPath: string): { + isVersioned: boolean; + currentVersion?: string; + versionPattern?: RegExp; + basePathBeforeVersion?: string; +} { + const normalizedPath = contentPath.replace(/\\/g, '/'); + + // Pattern for server versions (v5, v22.10, v24.6, v25.0, etc.) + // Handle both with and without leading slash + const serverMatch = normalizedPath.match(/(?:^|\/)server\/(v\d+(?:\.\d+)?)/); + + if (serverMatch) { + return { + isVersioned: true, + currentVersion: serverMatch[1], + versionPattern: /^v\d+(?:\.\d+)?$/, + basePathBeforeVersion: '/server' + }; + } + + // Pattern for client versions (1.0, 2.0, etc.) + const clientMatch = normalizedPath.match(/(?:^|\/)clients\/([^/]+)\/([^/]+)\/([\d.]+)/); + + if (clientMatch) { + return { + isVersioned: true, + currentVersion: clientMatch[3], + versionPattern: /^\d+\.\d+$/, + basePathBeforeVersion: `/clients/${clientMatch[1]}/${clientMatch[2]}` + }; + } + + return { isVersioned: false }; +} + +// Get available versions for a versioned path +export function getAvailableVersions(contentPath: string): VersionInfo[] { + const versionInfo = extractVersionInfo(contentPath); + if (!versionInfo.isVersioned || !versionInfo.basePathBeforeVersion) { + return []; + } + + const docsRoot = path.join(process.cwd(), 'src', 'content', 'docs'); + const basePath = path.join(docsRoot, ...versionInfo.basePathBeforeVersion.split('/').filter(Boolean)); + + try { + const entries = fs.readdirSync(basePath, { withFileTypes: true }); + const versionStrings: string[] = []; + + // Collect all valid version directories + for (const entry of entries) { + if (entry.isDirectory() && versionInfo.versionPattern?.test(entry.name)) { + versionStrings.push(entry.name); + } + } + + // Find the latest version using semver comparison + const latestVersion = findLatestVersion(versionStrings); + + // Create VersionInfo objects + const versions: VersionInfo[] = versionStrings.map(version => ({ + version, + label: version === latestVersion ? `${version} (Latest)` : version, + urlPath: `${versionInfo.basePathBeforeVersion}/${version}` + })); + + // Sort versions in descending order for display + versions.sort((a, b) => { + const aParsed = parseVersion(a.version); + const bParsed = parseVersion(b.version); + return compareVersions(bParsed, aParsed); // Reverse order for descending + }); + + return versions; + } catch (error) { + console.error(`Error getting versions for ${contentPath}:`, error); + return []; + } +} + +// Process sidebar items to ensure proper paths for versioned content +function processSidebarPaths(items: SidebarItem[], currentPath: string): SidebarItem[] { + const versionInfo = extractVersionInfo(currentPath); + + return items.map(item => { + const newItem = { ...item }; + + // If this is a link, ensure it uses forward slashes + if (newItem.link) { + // Replace all backslashes with forward slashes + newItem.link = newItem.link.replace(/\\/g, '/'); + + // If we're in versioned content, ensure it includes the version + if (versionInfo.isVersioned && versionInfo.currentVersion) { + // Check if the link already includes the base path and version + const linkHasVersion = newItem.link.includes(versionInfo.currentVersion); + + if (!linkHasVersion) { + // Prepend the versioned base path if not already there + const versionedBase = `${versionInfo.basePathBeforeVersion}/${versionInfo.currentVersion}`; + + // Remove leading slash from link for proper concatenation + const cleanLink = newItem.link.startsWith('/') ? newItem.link.slice(1) : newItem.link; + + // Only prepend if the link doesn't already start with the versioned base + if (!newItem.link.startsWith(versionedBase)) { + newItem.link = `${versionedBase}/${cleanLink}`; + } + } + } + } + + // Process child items recursively + if (newItem.items) { + newItem.items = processSidebarPaths(newItem.items, currentPath); + } + + return newItem; + }); +} + +// Main function to get sidebar configuration +export function getSidebarConfig(currentPath: string): { + sidebar: SidebarItem[]; + versionInfo?: { + isVersioned: boolean; + currentVersion?: string; + availableVersions?: VersionInfo[]; + }; +} { + try { + // Clean up the path + const cleanPath = currentPath.replace(/^\//, '').replace(/\/$/, '').toLowerCase(); + + + // Extract version information + const versionInfo = extractVersionInfo(cleanPath); + + // Try to find sidebar.json file + const sidebarPath = getSidebarPath(cleanPath); + let sidebar: SidebarItem[] = []; + + if (sidebarPath) { + // Load from file + const loadedSidebar = loadSidebarFromFile(sidebarPath); + if (loadedSidebar) { + sidebar = loadedSidebar; + } + } + + // If no sidebar loaded, generate from directory + if (sidebar.length === 0) { + const docsRoot = path.join(process.cwd(), 'src', 'content', 'docs'); + const contentDir = path.join(docsRoot, ...cleanPath.split('/').filter(Boolean)); + + // For versioned content, generate from the version directory + if (fs.existsSync(contentDir) && fs.statSync(contentDir).isDirectory()) { + sidebar = generateSidebarFromDirectory(contentDir, cleanPath); + } else { + // Try parent directory + const parentDir = path.dirname(contentDir); + if (fs.existsSync(parentDir) && fs.statSync(parentDir).isDirectory()) { + const parentPath = cleanPath.split('/').slice(0, -1).join('/'); + sidebar = generateSidebarFromDirectory(parentDir, parentPath); + } + } + } + + // Process autogenerate directives in loaded sidebar + sidebar = processSidebarItems(sidebar, cleanPath); + + // Process paths to ensure they're correct for versioned content + sidebar = processSidebarPaths(sidebar, cleanPath); + + + // Get available versions if versioned + let availableVersions: VersionInfo[] = []; + if (versionInfo.isVersioned) { + availableVersions = getAvailableVersions(cleanPath); + } + + return { + sidebar, + versionInfo: { + isVersioned: versionInfo.isVersioned, + currentVersion: versionInfo.currentVersion, + availableVersions + } + }; + } catch (error) { + console.error('[getSidebarConfig] Error:', error); + return { sidebar: [] }; + } +} + +// Process sidebar items to handle autogenerate directives +function processSidebarItems(items: SidebarItem[], basePath: string): SidebarItem[] { + return items.map(item => { + // Create a copy of the item + const processedItem = { ...item }; + + // Ensure link uses forward slashes if present + if (processedItem.link) { + processedItem.link = processedItem.link.replace(/\\/g, '/'); + } + + if (processedItem.autogenerate?.directory) { + const docsRoot = path.join(process.cwd(), 'src', 'content', 'docs'); + const dirPath = path.join(docsRoot, processedItem.autogenerate.directory); + + if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) { + const generatedItems = generateSidebarFromDirectory(dirPath, processedItem.autogenerate.directory); + return { + ...processedItem, + items: generatedItems + }; + } + } else if (processedItem.items) { + return { + ...processedItem, + items: processSidebarItems(processedItem.items, basePath) + }; + } + + return processedItem; + }); +} \ No newline at end of file diff --git a/docs/tools/convert.py b/docs/tools/convert.py new file mode 100644 index 00000000..2eca40ba --- /dev/null +++ b/docs/tools/convert.py @@ -0,0 +1,1564 @@ +#!/usr/bin/env python3 +""" +tools/convert_all.py + +Apply Markdown/MDX transformations in one pass—idempotent: + + 0. Copy docs/**/images → public/assets/img/doc-imgs, dedupe, convert rasters to .webp, copy SVGs, delete originals. + 1. Ensure frontmatter with title (inject from first H1 or default), and always one blank line after the closing `---`. + 2. Remove redundant H1 matching the title. + 3. Rename .md → .mdx. + 4. Update image refs to /assets/img/doc-imgs/… + 5. Convert :::tabs blocks → …. + 6. Inline & block @\[code{…}\] directives → with imports. + 7. Transform → Starlight syntax (warning→caution). + 8. Fix admonitions. + 9. Consolidate all imports into two deduplicated blocks: + • raw `?raw` imports + • Starlight component imports + leaving exactly one blank line after each block. + 10. Ensure `` and `` imports are present if used. + +Usage: + python3 tools/convert_all.py [path] [-v|--verbose] [--dry-run] +""" + +import sys +import re +import shutil +import hashlib +import argparse +from pathlib import Path +from PIL import Image +from typing import Tuple, List, Set + +SCRIPT_PATH = Path(__file__).resolve() +PROJECT_ROOT = SCRIPT_PATH.parent.parent +DOCS_DIR = PROJECT_ROOT / "src" / "content" / "docs" +ASSETS_IMG = PROJECT_ROOT / "public" / "assets" / "img" / "doc-imgs" +SAMPLES_ROOT = PROJECT_ROOT / "src" / "content" / "_samples" +TAB_IMPORT = 'import { Tabs, TabItem } from "@astrojs/starlight/components";' + +VERBOSE = False +DRY_RUN = False +img_converted = 0 +img_copied = 0 +files_updated = 0 + +# Compiled regex patterns for better performance +TITLE_RE = re.compile(r"^title:\s*(?P.+)$") +H1_RE = re.compile(r"^#\s+(?P<h1>.+)$") +BADGE_RE = re.compile(r"<Badge\s+([^>]*?)\/?>", re.IGNORECASE) +ATTR_RE = re.compile(r'(\w+)=[\'"]([^\'"]+)[\'"]') +ADMON_WITH_TITLE_RE= re.compile(r"^:::\s*(?P<type>\w+)\s+(?P<title>.+?)\s*(?:::)?$") +ADMON_TYPE_ONLY_RE = re.compile(r"^:::\s*(?P<type>\w+)\s*$") +CODE_DIR_RE = re.compile(r"@\[code\{(?P<key>[^}]+)\}\]\(@(?P<alias>[^:]+):(?P<files>[^)\n]+)\)") +SIMPLE_CODE_RE = re.compile(r"@\[code\{(?P<key>[^}]+)\}\]\((?P<rel>\.[^)]+)\)") +COMP_IMPORT_LINE = "import { Code, Tabs, TabItem } from '@astrojs/starlight/components';" +BADGE_IMPORT_LINE = "import { Badge } from '@astrojs/starlight/components';" +RAW_IMPORT_RE = re.compile(r"^import\s+\w+\s+from\s*['\"].+\?raw['\"];$") +COMPONENT_RE = re.compile(r"import\s*{\s*([^}]+)\s*}\s*from\s*['\"]@astrojs/starlight/components['\"];") +THEME_COMPONENT_RE = re.compile(r"import\s+\w+\s+from\s*['\"]@/components/ThemeAwareImages\.astro['\"];") + + +# Image processing +SUPPORTED_IMG_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff'} +SVG_EXTENSION = '.svg' + +EXT_LABEL = { + 'py': ('Python', 'python'), + 'js': ('JavaScript','javascript'), + 'ts': ('TypeScript','typescript'), + 'java': ('Java', 'java'), + 'cs': ('C#', 'csharp'), + 'go': ('Go', 'go'), + 'rs': ('Rust', 'rust'), + 'sh': ('Shell', 'bash'), + 'bash': ('Bash', 'bash'), + 'zsh': ('Zsh', 'zsh'), + 'yaml': ('YAML', 'yaml'), + 'yml': ('YAML', 'yaml'), + 'json': ('JSON', 'json'), + 'xml': ('XML', 'xml'), + 'html': ('HTML', 'html'), + 'css': ('CSS', 'css'), + 'scss': ('SCSS', 'scss'), + 'sass': ('Sass', 'sass'), +} + + +def log_verbose(msg: str) -> None: + """Log message only if verbose mode is enabled.""" + if VERBOSE: + print(msg) + + +def copy_all_images() -> None: + """Copy and convert images from both docs and assets directories.""" + global img_converted, img_copied + + # Define source directories to process + source_dirs = [ + (DOCS_DIR, "docs"), # Original docs images + (PROJECT_ROOT / "src" / "assets" / "img", "assets"), # Assets directory + ] + + seen_hashes = {} + + # Create assets directory if it doesn't exist + ASSETS_IMG.mkdir(parents=True, exist_ok=True) + + for source_base, description in source_dirs: + if not source_base.exists(): + log_verbose(f"Source directory {source_base} does not exist, skipping") + continue + + # For docs, look in images subdirectories; for assets, look directly + pattern = "**/images/**/*.*" if description == "docs" else "**/*.*" + + for img_path in source_base.rglob(pattern): + if not img_path.is_file(): + continue + + # Skip already converted webp files + if img_path.suffix.lower() == ".webp": + continue + + try: + # Calculate relative path based on source + if description == "docs": + rel_path = img_path.relative_to(DOCS_DIR) + else: + # For assets, preserve relative structure but handle logos specially + rel_from_assets = img_path.relative_to(source_base) + filename = img_path.name.lower() + + if "logo" in filename: + # Put logos in a special logo folder, preserving any subfolder structure + if rel_from_assets.parent != Path('.'): + rel_path = Path("logo") / rel_from_assets.parent / img_path.name + else: + rel_path = Path("logo") / img_path.name + else: + # For non-logo assets, don't add extra "assets" folder - use relative path directly + rel_path = rel_from_assets + + is_versioned = any(char.isdigit() for char in str(rel_path)) + ext = img_path.suffix.lower() + + # Calculate hash for deduplication (skip for SVGs to preserve them exactly) + if ext != SVG_EXTENSION: + data = img_path.read_bytes() + file_hash = hashlib.md5(data).hexdigest() + + # Skip duplicates unless versioned + if not is_versioned and file_hash in seen_hashes: + log_verbose(f"Skipping duplicate: {img_path}") + continue + + seen_hashes[file_hash] = img_path + + dest_path = ASSETS_IMG / rel_path + dest_path.parent.mkdir(parents=True, exist_ok=True) + + if not DRY_RUN: + if ext == SVG_EXTENSION: + # Copy SVG as-is + shutil.copy2(img_path, dest_path) + img_copied += 1 + log_verbose(f"Copied SVG: {img_path} -> {dest_path}") + elif ext in SUPPORTED_IMG_EXTENSIONS: + # Convert to WebP + webp_dest = dest_path.with_suffix(".webp") + with Image.open(img_path) as img: + img.save(webp_dest, format="WEBP", quality=80, method=6) + img_converted += 1 + log_verbose(f"Converted to WebP: {img_path} -> {webp_dest}") + + except Exception as e: + print(f"Error processing image {img_path}: {e}", file=sys.stderr) + continue + + # Clean up original images from ALL processed directories + if not DRY_RUN: + cleanup_all_original_images(source_dirs) + +def convert_numeric_titles_to_string(text: str) -> Tuple[str, bool]: + """Convert numeric-only titles in frontmatter to strings by wrapping them in quotes.""" + lines = text.splitlines() + changed = False + + # Check if document has frontmatter + if not lines or lines[0].strip() != '---': + return text, False + + try: + # Find the end of frontmatter + fm_end_idx = lines[1:].index('---') + 1 + except ValueError: + return text, False + + # Process frontmatter lines + for i in range(1, fm_end_idx): + line = lines[i] + + # Check for title field + title_match = re.match(r'^(\s*title:\s*)(.+)$', line) + if title_match: + prefix = title_match.group(1) + title_value = title_match.group(2).strip() + + # Check if title is purely numeric and not already quoted + if not (title_value.startswith('"') or title_value.startswith("'")): + try: + float(title_value) + # If we can convert to float and it matches numeric pattern, wrap in quotes + if re.match(r'^-?\d+(\.\d+)?$', title_value): + lines[i] = f'{prefix}"{title_value}"' + changed = True + log_verbose(f"Converted numeric title '{title_value}' to string") + except ValueError: + pass + + return "\n".join(lines), changed + +def cleanup_all_original_images(source_dirs) -> None: + """Remove original image files and empty directories from all source directories.""" + for source_base, description in source_dirs: + if not source_base.exists(): + continue + + pattern = "**/images/**/*.*" if description == "docs" else "**/*.*" + + for img_path in source_base.rglob(pattern): + if img_path.suffix.lower() in SUPPORTED_IMG_EXTENSIONS: + try: + img_path.unlink() + log_verbose(f"Removed original: {img_path}") + except Exception as e: + log_verbose(f"Could not remove {img_path}: {e}") + + # Remove empty image directories (only for docs) + if description == "docs": + for img_dir in source_base.rglob("**/images"): + try: + if img_dir.is_dir() and not any(img_dir.iterdir()): + img_dir.rmdir() + log_verbose(f"Removed empty directory: {img_dir}") + except Exception as e: + log_verbose(f"Could not remove directory {img_dir}: {e}") + + +def clean_converted_pngs_in_destination() -> None: + """Remove any PNG/JPG files that were accidentally copied to destination instead of converted.""" + if not ASSETS_IMG.exists(): + return + + for img_path in ASSETS_IMG.rglob("*.*"): + if img_path.suffix.lower() in SUPPORTED_IMG_EXTENSIONS: + # Check if there's a corresponding .webp file + webp_version = img_path.with_suffix(".webp") + if webp_version.exists(): + try: + img_path.unlink() + log_verbose(f"Removed unconverted copy: {img_path}") + except Exception as e: + log_verbose(f"Could not remove {img_path}: {e}") + else: + # Convert it now + try: + with Image.open(img_path) as img: + img.save(webp_version, format="WEBP", quality=80, method=6) + img_path.unlink() + log_verbose(f"Converted and removed: {img_path} -> {webp_version}") + except Exception as e: + log_verbose(f"Could not convert {img_path}: {e}") + + +def cleanup_original_images() -> None: + """Remove original image files and empty directories.""" + for img_path in DOCS_DIR.rglob("**/images/**/*.*"): + if img_path.suffix.lower() in SUPPORTED_IMG_EXTENSIONS | {SVG_EXTENSION}: + try: + img_path.unlink() + log_verbose(f"Removed original: {img_path}") + except Exception as e: + log_verbose(f"Could not remove {img_path}: {e}") + + # Remove empty image directories + for img_dir in DOCS_DIR.rglob("**/images"): + try: + if img_dir.is_dir() and not any(img_dir.iterdir()): + img_dir.rmdir() + log_verbose(f"Removed empty directory: {img_dir}") + except Exception as e: + log_verbose(f"Could not remove directory {img_dir}: {e}") + + +def ensure_frontmatter(text: str) -> Tuple[str, bool]: + """Ensure document has proper frontmatter with title.""" + lines = text.splitlines() + + if not lines or lines[0].strip() != '---': + # No frontmatter - create it + title = extract_title_from_content(lines) or "Untitled" + new_lines = remove_title_h1_if_matches(lines, title) + frontmatter = ['---', f'title: "{title}"', '---', ''] + return "\n".join(frontmatter + new_lines), True + + # Has frontmatter - ensure it has title + try: + fm_end_idx = lines[1:].index('---') + 1 + except ValueError: + return text, False + + # Check if title exists in frontmatter + has_title = any(TITLE_RE.match(line) for line in lines[1:fm_end_idx]) + + if not has_title: + # Add title from first H1 or default + title = extract_title_from_content(lines[fm_end_idx+1:]) or "Untitled" + lines.insert(fm_end_idx, f'title: "{title}"') + # Remove matching H1 after frontmatter + content_lines = remove_title_h1_if_matches(lines[fm_end_idx+2:], title) + lines = lines[:fm_end_idx+2] + content_lines + + # Ensure exactly one blank line after frontmatter + ensure_blank_line_after_frontmatter(lines, fm_end_idx + 1) + return "\n".join(lines), True + + return text, False + +def extract_title_from_content(lines: List[str]) -> str: + """Extract title from first H1 heading.""" + for line in lines: + if line.strip(): # Skip empty lines + match = H1_RE.match(line) + if match: + return match.group('h1').strip() + break # Stop at first non-empty line + return "" + +def normalize_powershell_language(text: str) -> Tuple[str, bool]: + """Normalize PowerShell language identifiers for proper syntax highlighting.""" + # Pattern to match code blocks with PowerShell variants (including indented ones) + pattern = re.compile(r'^(\s*)```(PowerShell|Powershell|POWERSHELL|pwsh|posh)\b', re.MULTILINE) + + def replacer(match): + indent = match.group(1) # Preserve the indentation + return f'{indent}```powershell' + + new_text = pattern.sub(replacer, text) + return (new_text, new_text != text) + +def remove_catalog_component(text: str) -> Tuple[str, bool]: + """Remove <Catalog/> component references.""" + # Pattern to match various forms of Catalog component + patterns = [ + re.compile(r'<Catalog\s*/>', re.IGNORECASE), # <Catalog/> + re.compile(r'<Catalog\s*></Catalog>', re.IGNORECASE), # <Catalog></Catalog> + re.compile(r'<Catalog\s*>\s*</Catalog>', re.IGNORECASE), # <Catalog> </Catalog> (with whitespace) + ] + + changed = False + new_text = text + + for pattern in patterns: + updated_text = pattern.sub('', new_text) + if updated_text != new_text: + changed = True + new_text = updated_text + + return (new_text, changed) + + +def remove_title_h1_if_matches(lines: List[str], title: str) -> List[str]: + """Remove H1 heading if it matches the title.""" + result = [] + title_removed = False + + for line in lines: + if not title_removed and line.strip(): + match = H1_RE.match(line) + if match and match.group('h1').strip() == title: + title_removed = True + continue + result.append(line) + + return result + + +def ensure_blank_line_after_frontmatter(lines: List[str], fm_end_idx: int) -> None: + """Ensure exactly one blank line after frontmatter.""" + # Remove existing blank lines + while fm_end_idx < len(lines) and not lines[fm_end_idx].strip(): + lines.pop(fm_end_idx) + + # Add exactly one blank line + if fm_end_idx < len(lines): + lines.insert(fm_end_idx, '') + + +def remove_redundant_h1(text: str) -> Tuple[str, bool]: + """Remove H1 that matches the frontmatter title.""" + lines = text.splitlines() + + if len(lines) < 3 or lines[0].strip() != '---': + return text, False + + try: + fm_end_idx = lines[1:].index('---') + 1 + except ValueError: + return text, False + + # Extract title from frontmatter + title = None + for line in lines[1:fm_end_idx]: + match = TITLE_RE.match(line) + if match: + title = match.group('title').strip().strip('"\' ') + break + + if not title: + return text, False + + # Look for matching H1 after frontmatter + for i in range(fm_end_idx + 1, len(lines)): + if not lines[i].strip(): + continue + + match = H1_RE.match(lines[i]) + if match and match.group('h1').strip() == title: + # Remove H1 and following blank line if present + lines.pop(i) + if i < len(lines) and not lines[i].strip(): + lines.pop(i) + return "\n".join(lines), True + break + + return text, False + + +def update_image_paths(text: str, md_path: Path) -> Tuple[str, bool]: + """Update image paths to point to assets directory, excluding theme-aware images.""" + # Skip processing if ThemeAwareImages components are present + if '<ThemeAwareImages' in text: + return text, False + + # Pattern to match images WITHOUT #light or #dark fragments + pattern = re.compile(r"(!\[[^\]]*\]\()(?P<rel>(?:\.\.?/)*images/[^)#]+)(?<!#light)(?<!#dark)(\))") + changed = False + + def replacer(match): + nonlocal changed + changed = True + + try: + src_path = (md_path.parent / match.group("rel")).resolve() + rel_path = src_path.relative_to(DOCS_DIR) + except (ValueError, OSError): + rel_path = Path(match.group("rel")) + + # Convert extensions to .webp for supported formats + if rel_path.suffix.lower() in SUPPORTED_IMG_EXTENSIONS: + rel_path = rel_path.with_suffix('.webp') + + return f"{match.group(1)}/assets/img/doc-imgs/{rel_path.as_posix()}{match.group(3)}" + + new_text = pattern.sub(replacer, text) + return new_text, changed + +def process_regular_image_paths(text: str, md_path: Path) -> str: + """Process regular image paths that aren't in ThemeAwareImages components.""" + # Updated pattern to capture theme fragments, size specifications, and trailing spaces + pattern = re.compile(r"(!\[[^\]]*\]\()(?P<rel>(?:\.\.?/)*images/[^)#=]+)(?P<fragment>#(?:light|dark))?(?P<size>=x?\d+)?\s*(\))") + + def replacer(match): + try: + rel_path_str = match.group("rel") + fragment = match.group("fragment") or "" + # Note: we're dropping the size specification (=x200, etc.) and trailing spaces + + src_path = (md_path.parent / rel_path_str).resolve() + rel_path = src_path.relative_to(DOCS_DIR) + except (ValueError, OSError): + rel_path = Path(rel_path_str) + + # Convert extensions to .webp for supported formats + if rel_path.suffix.lower() in SUPPORTED_IMG_EXTENSIONS: + rel_path = rel_path.with_suffix('.webp') + + return f"{match.group(1)}/assets/img/doc-imgs/{rel_path.as_posix()}{fragment}{match.group(4)}" + + return pattern.sub(replacer, text) + + +def convert_theme_images_to_component(text: str, md_path: Path) -> Tuple[str, bool]: + """Convert image pairs with #light and #dark to ThemeAwareImages component.""" + + # Updated patterns to handle trailing spaces, size specifications, and SVGs + light_pattern = re.compile(r'!\[([^\]]*)\]\(([^)#=]+?)#light\s*(?:=x?\d+)?\s*\)') + dark_pattern = re.compile(r'!\[([^\]]*)\]\(([^)#=]+?)#dark\s*(?:=x?\d+)?\s*\)') + + # Find all images with theme fragments + light_matches = list(light_pattern.finditer(text)) + dark_matches = list(dark_pattern.finditer(text)) + + if not light_matches and not dark_matches: + return text, False + + # Build a map of image pairs to replace + components_to_add = [] + positions_to_remove = set() + + # Process each light image to find its dark counterpart + for light_match in light_matches: + alt_text = light_match.group(1) + light_path = light_match.group(2).strip() + + # Look for corresponding dark image + dark_match = None + dark_path = None + + # Try to find a dark image with similar path + for dm in dark_matches: + dark_match_path = dm.group(2).strip() + # Check if paths are related (same base name or -dark variant) + light_base = light_path.replace('.png', '').replace('.jpg', '').replace('.webp', '').replace('.svg', '') + dark_base = dark_match_path.replace('-dark.png', '').replace('-dark.jpg', '').replace('-dark.webp', '').replace('-dark.svg', '').replace('_dark.png', '').replace('_dark.jpg', '').replace('_dark.webp', '').replace('_dark.svg', '') + + if light_base == dark_base or dark_match_path.startswith(light_base): + dark_match = dm + dark_path = dark_match_path + break + + # If we found a pair, create component + if dark_match and dark_path: + # Use the earlier position for component placement + component_pos = min(light_match.start(), dark_match.start()) + + # Calculate the actual image paths + light_final_path = find_and_calculate_image_path(light_path, md_path) + dark_final_path = find_and_calculate_image_path(dark_path, md_path) + + if light_final_path and dark_final_path: + # Add width and height for SVGs + width_height_attrs = "" + if light_path.lower().endswith('.svg') or dark_path.lower().endswith('.svg'): + width_height_attrs = '\n width="800"\n height="600"' + + component = f'<ThemeAwareImages\n light="{light_final_path}"\n dark="{dark_final_path}"\n alt="{alt_text}"{width_height_attrs}\n/>' + + components_to_add.append((component_pos, component)) + positions_to_remove.add((light_match.start(), light_match.end())) + positions_to_remove.add((dark_match.start(), dark_match.end())) + + if not components_to_add: + return text, False + + # Sort positions for removal in reverse order + removal_positions = sorted(positions_to_remove, key=lambda x: x[0], reverse=True) + + # Remove original images + new_text = text + for start, end in removal_positions: + new_text = new_text[:start] + new_text[end:] + + # Sort components by position in reverse order and add them + components_to_add.sort(key=lambda x: x[0], reverse=True) + + for pos, component in components_to_add: + # Adjust position based on previous removals + adjusted_pos = pos + for start, end in removal_positions: + if start < pos: + adjusted_pos -= (end - start) + + # Ensure we don't go below 0 + adjusted_pos = max(0, adjusted_pos) + + new_text = new_text[:adjusted_pos] + component + new_text[adjusted_pos:] + + # Add import if we added any ThemeAwareImages components + has_theme_components = '<ThemeAwareImages' in new_text + if has_theme_components: + new_text = ensure_theme_component_import(new_text) + + return new_text, True + +def find_and_calculate_image_path(original_path: str, md_path: Path) -> str: + """Find the actual image file and calculate relative path from MDX to image.""" + # Extract just the filename from the original path + filename = Path(original_path).name + + # Convert extension to .webp if it's a supported format (but not SVG) + if filename.lower().endswith(('.png', '.jpg', '.jpeg')): + filename = filename.rsplit('.', 1)[0] + '.webp' + # Keep SVG files as-is + elif filename.lower().endswith('.svg'): + pass # SVGs stay as SVGs + + # Search for the file in the assets directory + # Try to find it based on the document's relative path structure + try: + # Get the relative path of the MDX file from docs root + mdx_rel_path = md_path.relative_to(DOCS_DIR) + + # Construct possible image paths + possible_paths = [] + + # Try exact path structure under doc-imgs + mdx_dir_parts = mdx_rel_path.parent.parts + if mdx_dir_parts: + # Try with full path structure + possible_paths.append(ASSETS_IMG / Path(*mdx_dir_parts) / 'images' / filename) + # Try without 'images' subdirectory + possible_paths.append(ASSETS_IMG / Path(*mdx_dir_parts) / filename) + + # Also try a general search + for img_path in ASSETS_IMG.rglob(filename): + if img_path not in possible_paths: + possible_paths.append(img_path) + + # Find the first existing path + target_image_path = None + for path in possible_paths: + if path.exists(): + target_image_path = path + break + + if not target_image_path: + log_verbose(f"Could not find image file: {filename}") + return original_path + + # Calculate relative path from MDX file to image + # This needs to go from src/content/docs/... to public/assets/img/doc-imgs/... + + # Calculate how many directories up we need to go from the MDX file + mdx_depth = len(md_path.parent.relative_to(DOCS_DIR).parts) + 1 # +1 for the docs folder itself + + # Go up to src/content level (2 more levels up) + total_up = mdx_depth + 2 + + # Build the relative path + up_path = "../" * total_up + + # Path from project root to the image + image_from_root = target_image_path.relative_to(PROJECT_ROOT) + + # Since we're going to project root and then to public/assets/... + relative_path = up_path + image_from_root.as_posix() + + # Remove 'public/' from the beginning of the path if it exists + relative_path = relative_path.replace('public/', '', 1) + + return relative_path + + except Exception as e: + log_verbose(f"Error calculating image path for {original_path}: {e}") + return original_path + +def clean_code_block_languages(text: str) -> Tuple[str, bool]: + """Remove :no-line-numbers and similar suffixes from code block languages.""" + changed = False + + # Pattern 1: Code blocks with language + :no-line-numbers + # Example: ```javascript:no-line-numbers -> ```javascript + pattern1 = re.compile(r'^```(\w+):no-line-numbers\b', re.MULTILINE) + new_text = pattern1.sub(r'```\1', text) + if new_text != text: + changed = True + text = new_text + + # Pattern 2: Code blocks with only :no-line-numbers (no language) + # Example: ```:no-line-numbers -> ``` + pattern2 = re.compile(r'^```:no-line-numbers\b', re.MULTILINE) + new_text = pattern2.sub('```', text) + if new_text != text: + changed = True + text = new_text + + return text, changed + + +def convert_tabs(text: str) -> Tuple[str, bool]: + """Convert :::tabs and ::::tabs blocks to <Tabs> components.""" + changed = False + + # Handle both ::: and :::: variants (4 colons first, then 3) + patterns = [ + r'(^[ \t]*::::\s*tabs[ \t]*\r?\n)(.*?)(^[ \t]*::::[ \t]*\r?\n?)', + r'(^[ \t]*:::\s*tabs[ \t]*\r?\n)(.*?)(^[ \t]*:::[ \t]*\r?\n?)' + ] + + def process_tab_block(match): + nonlocal changed + changed = True + + content = match.group(2) + lines = content.splitlines() + + # Parse tab items + items = [] + current_label = None + current_content = [] + + for line in lines: + # Check if this line starts a new tab + if re.match(r'^[ \t]*@tab\s+', line): + # Save previous tab if exists + if current_label is not None: + items.append((current_label, current_content)) + + # Start new tab + current_label = line.strip()[5:].strip() # Remove '@tab ' prefix + current_content = [] + else: + # Add to current tab's content (even if no current tab yet) + current_content.append(line) + + # Save last tab + if current_label is not None: + items.append((current_label, current_content)) + + # If no tabs were found, return original content + if not items: + return match.group(0) + + # Build output + result = "<Tabs>\n" + for label, content_lines in items: + result += f' <TabItem label="{label}">\n' + for content_line in content_lines: + # Indent content properly, but preserve existing indentation + if content_line.strip(): # Don't indent empty lines + result += f' {content_line}\n' + else: + result += '\n' + result += " </TabItem>\n" + result += "</Tabs>\n" + + return result + + # Process each pattern + for pattern in patterns: + new_text = re.sub(pattern, process_tab_block, text, flags=re.DOTALL | re.MULTILINE) + if new_text != text: + changed = True + text = new_text + + return text, changed + + +def transform_badges(text: str) -> Tuple[str, bool]: + """Transform Badge components to Starlight syntax.""" + def replacer(match): + attrs = dict(ATTR_RE.findall(match.group(1))) + text_val = attrs.get('text') or attrs.get('label') or '' + variant = (attrs.get('type') or attrs.get('variant') or '').lower() + + # Map variants to Starlight-compatible values + if variant == 'warning': + variant = 'caution' + elif variant == 'info': + variant = 'note' + + return f'<Badge text="{text_val}" variant="{variant}" />' + + new_text = BADGE_RE.sub(replacer, text) + if new_text != text: + return insert_import(new_text, BADGE_IMPORT_LINE), True + return text, False + +def fix_admonitions(text: str) -> Tuple[str, bool]: + """Fix admonition syntax.""" + lines = text.splitlines() + changed = False + + for i, line in enumerate(lines): + # Handle admonitions with titles + match = ADMON_WITH_TITLE_RE.match(line) + if match: + lines[i] = f":::{match.group('type')}[{match.group('title').strip()}]" + changed = True + continue + + # Handle type-only admonitions + match = ADMON_TYPE_ONLY_RE.match(line) + if match: + lines[i] = f":::{match.group('type')}" + changed = True + + return ("\n".join(lines), changed) if changed else (text, False) + + +def sanitize_var(key: str, lang: str, fname: str) -> str: + """Create a sanitized variable name.""" + def clean(s): + return re.sub(r'[^0-9A-Za-z_]', '_', s) + + base = Path(fname).stem + return f"{clean(lang.lower())}_{clean(key)}_{clean(base)}" + + +def find_sample_path(rel: str, doc_path: Path) -> Path: + """Find sample file path with better error handling.""" + rel_path = Path(rel.strip()) + + # Try relative to current document + if rel_path.parts and rel_path.parts[0] in ('.', '..'): + doc_relative = (doc_path.parent / rel_path).resolve() + if doc_relative.exists() and doc_relative.is_file(): + return doc_relative + + # Try relative to samples root + sample_path = (SAMPLES_ROOT / rel_path).resolve() + if sample_path.exists() and sample_path.is_file(): + return sample_path + + # Search by filename in samples root + filename = rel_path.name + if filename: + try: + matches = list(SAMPLES_ROOT.rglob(filename)) + if matches: + if len(matches) > 1: + log_verbose(f"Warning: Multiple matches for '{filename}', using first: {matches[0]}") + return matches[0] + except ValueError as e: + raise FileNotFoundError(f"Invalid pattern '{filename}' for rglob: {e}") from e + + raise FileNotFoundError(f"Cannot locate sample '{rel}' in any search path") + + +def process_inline_code_refs(text: str, path: Path) -> Tuple[str, bool]: + """Process inline code references.""" + imports = [] + changed = False + + def replacer(match): + nonlocal changed + changed = True + + key = match.group('key') + rel = match.group('rel').strip() + + try: + src_path = (path.parent / rel).resolve() + ext = src_path.suffix.lstrip('.').lower() + lang = EXT_LABEL.get(ext, (None, ext))[1] + var_name = sanitize_var(key, lang, str(src_path)) + import_path = "/" + src_path.relative_to(PROJECT_ROOT).as_posix() + "?raw" + imports.append(f"import {var_name} from '{import_path}';") + return f"```{lang}\n{var_name}\n```" + except Exception as e: + log_verbose(f"Error processing inline code ref {rel}: {e}") + return match.group(0) # Return original if error + + new_text = SIMPLE_CODE_RE.sub(replacer, text) + if not changed: + return text, False + + # Insert imports after frontmatter + return insert_raw_imports(new_text, imports), True + + +def process_code_directives(text: str, path: Path) -> Tuple[str, bool]: + """Process code directive blocks.""" + imports = [] + changed = False + + def replacer(match): + nonlocal changed + changed = True + + key = match.group('key') + files = match.group('files').split(';') + entries = [] + + for file_ref in files: + try: + sample_path = find_sample_path(file_ref, path) + ext = Path(file_ref).suffix.lstrip('.') + label, lang = EXT_LABEL.get(ext, (ext, ext)) + var_name = sanitize_var(key, lang, file_ref) + rel_path = sample_path.relative_to(PROJECT_ROOT).as_posix() + imports.append(f"import {var_name} from '/{rel_path}?raw';") + entries.append((label, lang, var_name)) + except FileNotFoundError: + log_verbose(f"Could not find sample file: {file_ref}") + continue + + if not entries: + return "" + + imports.append(COMP_IMPORT_LINE) + + if len(entries) > 1: + # Multiple files - use tabs + result = ["<Tabs>"] + for label, lang, var_name in entries: + result.extend([ + f' <TabItem label="{label}">', + f' <Code lang="{lang}" code={{{var_name}}} />', + ' </TabItem>', + ]) + result.append("</Tabs>") + return "\n".join(result) + else: + # Single file + label, lang, var_name = entries[0] + return f'<Code lang="{lang}" code={{{var_name}}} />' + + new_text = CODE_DIR_RE.sub(replacer, text) + if not changed: + return text, False + + return insert_raw_imports(new_text, imports), True + + +def insert_import(text: str, import_line: str) -> str: + """Insert an import line after frontmatter if not already present.""" + if import_line in text: + return text + + lines = text.splitlines() + insert_idx = find_import_insertion_point(lines) + + # Ensure proper spacing + if insert_idx > 0 and lines[insert_idx - 1].strip(): + lines.insert(insert_idx, '') + insert_idx += 1 + + lines.insert(insert_idx, import_line) + + if insert_idx + 1 < len(lines) and lines[insert_idx + 1].strip(): + lines.insert(insert_idx + 1, '') + + return "\n".join(lines) + + +def insert_raw_imports(text: str, imports: List[str]) -> str: + """Insert raw import statements after frontmatter.""" + if not imports: + return text + + # Deduplicate imports + unique_imports = [] + for imp in imports: + if imp not in unique_imports: + unique_imports.append(imp) + + lines = text.splitlines() + insert_idx = find_import_insertion_point(lines) + + # Insert imports with proper spacing + if insert_idx > 0 and lines[insert_idx - 1].strip(): + lines.insert(insert_idx, '') + insert_idx += 1 + + for imp in reversed(unique_imports): + lines.insert(insert_idx, imp) + + if insert_idx + len(unique_imports) < len(lines) and lines[insert_idx + len(unique_imports)].strip(): + lines.insert(insert_idx + len(unique_imports), '') + + return "\n".join(lines) + + +def find_import_insertion_point(lines: List[str]) -> int: + """Find where to insert import statements.""" + if not lines or lines[0].strip() != '---': + return 0 + + try: + fm_end_idx = lines[1:].index('---') + 1 + return fm_end_idx + 1 + except ValueError: + return 0 + + +def extract_starlight_components(text: str) -> Set[str]: + """Extract used Starlight components from text.""" + components = set() + for match in COMPONENT_RE.finditer(text): + for name in match.group(1).split(','): + components.add(name.strip()) + return components + + +def consolidate_imports(text: str) -> Tuple[str, bool]: + """Consolidate all imports into organized blocks.""" + lines = text.splitlines() + + # Find frontmatter end + fm_end_idx = -1 + if lines and lines[0].strip() == '---': + try: + fm_end_idx = lines[1:].index('---') + 1 + except ValueError: + pass + + header_lines = lines[:fm_end_idx + 1] if fm_end_idx != -1 else [] + body_lines = lines[fm_end_idx + 1:] if fm_end_idx != -1 else lines + + # Separate imports from content + raw_imports = [] + component_names = set() + theme_component_imports = [] + content_lines = [] + + for line in body_lines: + stripped = line.strip() + if RAW_IMPORT_RE.match(stripped): + if stripped not in [imp.strip() for imp in raw_imports]: + raw_imports.append(line) + elif COMPONENT_RE.match(stripped): + match = COMPONENT_RE.match(stripped) + if match: + for name in match.group(1).split(','): + component_names.add(name.strip()) + elif THEME_COMPONENT_RE.match(stripped): + if stripped not in [imp.strip() for imp in theme_component_imports]: + theme_component_imports.append(line) + else: + content_lines.append(line) + + # Rebuild file + result = [] + + # Add header + if header_lines: + result.extend(header_lines) + + # Add theme component imports first + if theme_component_imports: + if result and result[-1].strip(): + result.append('') + result.extend(theme_component_imports) + result.append('') + + # Add raw imports + if raw_imports: + if result and result[-1].strip(): + result.append('') + result.extend(raw_imports) + result.append('') + + # Add starlight component imports + if component_names: + if result and result[-1].strip(): + result.append('') + sorted_components = ', '.join(sorted(component_names)) + result.append(f"import {{ {sorted_components} }} from '@astrojs/starlight/components';") + result.append('') + + # Add content + if content_lines: + if result and result[-1].strip(): + result.append('') + + # Clean up consecutive blank lines in content + cleaned_content = [] + prev_blank = False + for line in content_lines: + is_blank = not line.strip() + if is_blank and prev_blank: + continue + cleaned_content.append(line) + prev_blank = is_blank + + result.extend(cleaned_content) + + # Remove trailing blank lines + while result and not result[-1].strip(): + result.pop() + + new_text = "\n".join(result) + if result: + new_text += "\n" + + return new_text, (text != new_text) + + +def markdown_autolinks_in_tables_to_mdx(text: str) -> Tuple[str, bool]: + """Convert Markdown autolinks in tables to MDX links.""" + autolink_re = re.compile(r"<((?:https?://|www\.)[^>]+)>") + table_row_re = re.compile(r"^\s*\|.*\|$") + table_separator_re = re.compile(r"^\s*\|(?:\s*:?-+:?\s*\|)+") + + def replace_autolink(match): + url = match.group(1) + display_text = re.sub(r"^https?://", "", url) + display_text = re.sub(r"^www\.", "", display_text) + display_text = display_text.rstrip('/') + return f"[{display_text or url}]({url})" + + lines = text.splitlines() + new_lines = [] + changed = False + + for line in lines: + if table_row_re.match(line) and not table_separator_re.match(line): + parts = line.split('|') + processed_parts = [] + + for part in parts: + new_part, num_subs = autolink_re.subn(replace_autolink, part) + if num_subs > 0: + changed = True + processed_parts.append(new_part) + + new_lines.append("|".join(processed_parts)) + else: + new_lines.append(line) + + return ("\n".join(new_lines), changed) if changed else (text, False) + + +def close_br_tags(text: str) -> Tuple[str, bool]: + """Ensure BR and WBR tags are properly closed for MDX.""" + new_text = re.sub(r'<(br|wbr)(?!/>)\s*/?>', r'<\1/>', text) + return (new_text, new_text != text) + +def fix_badge_duplicates(text: str) -> Tuple[str, bool]: + """Fix Badge components with duplicate closing tags.""" + # Pattern to match self-closing Badge followed by closing tag + # Matches: <Badge ...attributes... /></Badge> + pattern = re.compile(r'<Badge\s+([^>]*?)\s*/>\s*</Badge>', re.IGNORECASE) + + def replacer(match): + attributes = match.group(1) + return f'<Badge {attributes} />' + + new_text = pattern.sub(replacer, text) + return (new_text, new_text != text) + + +def remove_html_comments(text: str) -> Tuple[str, bool]: + """Remove HTML comments.""" + new_text = re.sub(r'<!--[\s\S]*?-->', '', text) + return (new_text, new_text != text) + + +def fix_extraneous_closing_brace(text: str) -> Tuple[str, bool]: + """Fix extra closing braces in code props.""" + pattern = re.compile(r'(code=\{`[\s\S]*?`\})\}') + new_text = pattern.sub(r'\1', text) + return (new_text, new_text != text) + + +def rename_md_to_mdx(base: Path) -> None: + """Rename .md files to .mdx.""" + if DRY_RUN: + md_files = list(base.rglob("*.md")) + if md_files: + print(f"Would rename {len(md_files)} .md files to .mdx") + return + + for md_file in base.rglob("*.md"): + mdx_file = md_file.with_suffix(".mdx") + if not mdx_file.exists(): + md_file.rename(mdx_file) + log_verbose(f"Renamed: {md_file} -> {mdx_file}") + +def remove_sink_component(text: str) -> Tuple[str, bool]: + """Remove specific Vue.js component template and script block.""" + vue_component_pattern = re.compile( + r'<template>\s*' + r'<div>\s*' + r'<label for="connector">Select Connector Type:</label>\s*' + r'<select id="connector" v-model="selectedConnector">\s*' + r'<option v-for="type in connectorTypes" :value="type">\{\{ type \}\}</option>\s*' + r'</select>\s*' + r'</div>\s*' + r'</template>\s*' + r'<script>\s*' + r'export default \{\s*' + r'data\(\) \{\s*' + r'return \{\s*' + r'selectedConnector: "serilog-sink",\s*//\s*Default connector type\s*' + r'connectorTypes: \["serilog-sink", "http-sink", "custom-sink"\],\s*//\s*Add more connector types as needed\s*' + r'\};\s*' + r'\},\s*' + r'\};\s*' + r'</script>', + re.DOTALL | re.MULTILINE + ) + + new_text = vue_component_pattern.sub('', text) + return (new_text, new_text != text) + +def escape_generic_types_in_tables(text: str) -> Tuple[str, bool]: + """Escape generic type syntax in markdown tables for MDX compatibility.""" + table_row_re = re.compile(r"^\s*\|.*\|$") + table_separator_re = re.compile(r"^\s*\|(?:\s*:?-+:?\s*\|)+") + + # Pattern to match generic types like dict<string,string>, List<T>, etc. + generic_type_pattern = re.compile(r'(\w+)<([^>]+)>') + + def escape_generics(match): + type_name = match.group(1) + type_params = match.group(2) + return f'{type_name}\\<{type_params}\\>' + + lines = text.splitlines() + new_lines = [] + changed = False + + for line in lines: + if table_row_re.match(line) and not table_separator_re.match(line): + # This is a table row (not separator) + new_line = generic_type_pattern.sub(escape_generics, line) + if new_line != line: + changed = True + new_lines.append(new_line) + else: + new_lines.append(line) + + return ("\n".join(new_lines), changed) if changed else (text, False) + +def clean_image_size_specs(text: str) -> Tuple[str, bool]: + """Remove size specifications like =x200 from image references.""" + # Pattern to match size specs like =x200, =200x150, =200, etc. + pattern = re.compile(r'(!\[[^\]]*\]\([^)]+?)=x?\d+(?:x\d+)?(\))') + + new_text = pattern.sub(r'\1\2', text) + return (new_text, new_text != text) + +def ensure_theme_component_import(text: str) -> str: + """Ensure ThemeAwareImages import is present.""" + import_line = "import ThemeAwareImages from '@/components/ThemeAwareImages.astro';" + + # Check if import already exists + if import_line in text or "import ThemeAwareImages" in text: + return text + + lines = text.splitlines() + insert_idx = find_import_insertion_point(lines) + + # Add import with proper spacing + if insert_idx > 0 and lines[insert_idx - 1].strip(): + lines.insert(insert_idx, '') + insert_idx += 1 + + lines.insert(insert_idx, import_line) + + if insert_idx + 1 < len(lines) and lines[insert_idx + 1].strip(): + lines.insert(insert_idx + 1, '') + + return "\n".join(lines) + +def process_file(path: Path) -> None: + """Apply all transformations to a single MDX file.""" + global files_updated + + try: + original_text = path.read_text(encoding="utf-8") + text = original_text + + # Apply all transformations + transformations = [ + ("frontmatter", lambda t: ensure_frontmatter(t)), + ("frontmatter_syntax", lambda t: convert_frontmatter_syntax(t)), + ("remove_sink_component", lambda t: remove_sink_component(t)), + ("remove_cloud_banner", lambda t: remove_cloud_banner_component(t)), + ("remove_catalog", lambda t: remove_catalog_component(t)), + ("numeric_titles", lambda t: convert_numeric_titles_to_string(t)), + ("remove_hope_icon", lambda t: remove_hope_icon_component(t)), + ("theme_images", lambda t: convert_theme_images_to_component(t, path)), + ("image_paths", lambda t: update_image_paths(t, path)), + ("inline_code_refs", lambda t: process_inline_code_refs(t, path)), + ("remove_curl_from_code", lambda t: remove_curl_from_code_directives(t)), + ("redundant_h1", lambda t: remove_redundant_h1(t)), + ("clean_code_blocks", lambda t: clean_code_block_languages(t)), + ("normalize_powershell", lambda t: normalize_powershell_language(t)), + ("tabs", lambda t: convert_tabs(t)), + ("badges", lambda t: transform_badges(t)), + ("fix_badge_duplicates", lambda t: fix_badge_duplicates(t)), + ("admonitions", lambda t: fix_admonitions(t)), + ("code_directives", lambda t: process_code_directives(t, path)), + ("closing_braces", lambda t: fix_extraneous_closing_brace(t)), + ("table_autolinks", lambda t: markdown_autolinks_in_tables_to_mdx(t)), + ("escape_generic_types", lambda t: escape_generic_types_in_tables(t)), + ("br_tags", lambda t: close_br_tags(t)), + ("html_comments", lambda t: remove_html_comments(t)), + ("consolidate_imports", lambda t: consolidate_imports(t)), + ("clean_image_size_specs", lambda t: clean_image_size_specs(t)), + ] + + changed_any = False + for step_name, transform_func in transformations: + try: + text, step_changed = transform_func(text) + if step_changed: + changed_any = True + log_verbose(f"Applied {step_name} to {path}") + except Exception as e: + print(f"Error in {step_name} transformation for {path}: {e}", file=sys.stderr) + continue + + # Ensure required component imports are present + text, imports_changed = ensure_component_imports(text) + if imports_changed: + changed_any = True + + # Ensure trailing newline + if text and not text.endswith('\n'): + text += '\n' + if original_text.rstrip('\n') != text.rstrip('\n'): + changed_any = True + + # Write back if changed + if original_text != text: + if not DRY_RUN: + path.write_text(text, encoding="utf-8") + files_updated += 1 + log_verbose(f"Updated: {path}") + else: + print(f"Would update: {path}") + files_updated += 1 + elif changed_any: + log_verbose(f"Processed {path} (no net changes)") + + except Exception as e: + print(f"Error processing file {path}: {e}", file=sys.stderr) + + +def remove_cloud_banner_component(text: str) -> Tuple[str, bool]: + """Remove <CloudBanner/> component references.""" + # Pattern to match various forms of CloudBanner component + patterns = [ + re.compile(r'<CloudBanner\s*/>', re.IGNORECASE), # <CloudBanner/> + re.compile(r'<CloudBanner\s*></CloudBanner>', re.IGNORECASE), # <CloudBanner></CloudBanner> + re.compile(r'<CloudBanner\s*>\s*</CloudBanner>', re.IGNORECASE), # <CloudBanner> </CloudBanner> (with whitespace) + ] + + changed = False + new_text = text + + for pattern in patterns: + updated_text = pattern.sub('', new_text) + if updated_text != new_text: + changed = True + new_text = updated_text + + return (new_text, changed) + + +def ensure_component_imports(text: str) -> Tuple[str, bool]: + """Ensure required component imports are present.""" + existing_components = extract_starlight_components(text) + required_components = set() + needs_cloud_banner = False + + # Check what components are used + if '<Code ' in text: + required_components.add('Code') + if '<Tabs' in text or '<TabItem' in text: + required_components.update(['Tabs', 'TabItem']) + if '<Badge' in text: + required_components.add('Badge') + + # Handle Starlight components + missing_components = required_components - existing_components + starlight_changed = False + + if missing_components: + # Remove existing component imports + lines = [] + for line in text.splitlines(): + if not COMPONENT_RE.match(line.strip()): + lines.append(line) + + # Add consolidated import + all_components = existing_components | required_components + import_line = f"import {{ {', '.join(sorted(all_components))} }} from '@astrojs/starlight/components';" + text = insert_import("\n".join(lines), import_line) + starlight_changed = True + + return text, (starlight_changed) + +def convert_frontmatter_syntax(text: str) -> Tuple[str, bool]: + """Convert Markdown frontmatter syntax to MDX syntax.""" + # Pattern to match {{ $frontmatter.variable_name }} + pattern = re.compile(r'\{\{\s*\$frontmatter\.(\w+)\s*\}\}') + + def replacer(match): + variable_name = match.group(1) + return f"{{frontmatter.{variable_name}}}" + + new_text = pattern.sub(replacer, text) + return (new_text, new_text != text) + +def remove_curl_from_code_directives(text: str) -> Tuple[str, bool]: + """Remove 'curl', 'request', and 'response' from @[code{...}] directives, leaving empty braces.""" + # Pattern to match @[code{curl}], @[code{request}], or @[code{response}] + pattern = re.compile(r'@\[code\{(?:curl|request|response)\}\]', re.IGNORECASE) + + new_text = pattern.sub('@[code{}]', text) + return (new_text, new_text != text) + +def validate_environment() -> bool: + """Validate that required directories exist.""" + missing_dirs = [] + + if not PROJECT_ROOT.exists(): + missing_dirs.append(f"PROJECT_ROOT: {PROJECT_ROOT}") + if not SAMPLES_ROOT.exists(): + missing_dirs.append(f"SAMPLES_ROOT: {SAMPLES_ROOT}") + + if missing_dirs: + print("Missing required directories:", file=sys.stderr) + for dir_path in missing_dirs: + print(f" {dir_path}", file=sys.stderr) + return False + + return True + +def rename_readme_to_index(base: Path) -> None: + """Rename README.md/README.mdx files to index.md/index.mdx.""" + readme_files_renamed = 0 + + # Find all README files (case-insensitive) + readme_patterns = ["README.md", "readme.md", "Readme.md", "README.mdx", "readme.mdx", "Readme.mdx"] + + for pattern in readme_patterns: + for readme_file in base.rglob(pattern): + # Determine the new filename based on the original extension + if readme_file.suffix.lower() == '.md': + index_file = readme_file.parent / "index.md" + else: # .mdx + index_file = readme_file.parent / "index.mdx" + + # Only rename if index file doesn't already exist + if not index_file.exists(): + if not DRY_RUN: + readme_file.rename(index_file) + log_verbose(f"Renamed README to index: {readme_file} -> {index_file}") + else: + print(f"Would rename: {readme_file} -> {index_file}") + readme_files_renamed += 1 + else: + log_verbose(f"Skipping {readme_file} - index file already exists") + + if readme_files_renamed > 0: + action_word = "Would rename" if DRY_RUN else "Renamed" + print(f"{action_word} {readme_files_renamed} README files to index files") + +def remove_hope_icon_component(text: str) -> Tuple[str, bool]: + """Remove HopeIcon component references.""" + # Pattern to match various forms of HopeIcon component + patterns = [ + re.compile(r'<HopeIcon\s+[^>]*?/>', re.IGNORECASE), # <HopeIcon ... /> + re.compile(r'<HopeIcon\s+[^>]*?>\s*</HopeIcon>', re.IGNORECASE), # <HopeIcon ...></HopeIcon> + re.compile(r'<HopeIcon\s*>\s*</HopeIcon>', re.IGNORECASE), # <HopeIcon></HopeIcon> (no attributes) + ] + + changed = False + new_text = text + + for pattern in patterns: + updated_text = pattern.sub('', new_text) + if updated_text != new_text: + changed = True + new_text = updated_text + + return (new_text, changed) + +def print_summary() -> None: + """Print summary of operations performed.""" + action_word = "Would process" if DRY_RUN else "Processed" + print(f"\n{action_word} {files_updated} files") + + if img_converted > 0: + action_word = "Would convert" if DRY_RUN else "Converted" + print(f"{action_word} {img_converted} images to WebP") + + if img_copied > 0: + action_word = "Would copy" if DRY_RUN else "Copied" + print(f"{action_word} {img_copied} SVG files") + + + + +def main(): + """Main entry point.""" + global VERBOSE, DRY_RUN + + parser = argparse.ArgumentParser( + description="Convert Markdown/MDX files for Starlight theme", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__ + ) + parser.add_argument( + "path", + nargs="?", + help="Path to docs directory (default: auto-detected)" + ) + parser.add_argument( + "-v", "--verbose", + action="store_true", + help="Show detailed output" + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Show what would be done without making changes" + ) + + args = parser.parse_args() + + VERBOSE = args.verbose + DRY_RUN = args.dry_run + + # Validate environment + if not validate_environment(): + sys.exit(1) + + # Determine base directory + base_dir = Path(args.path) if args.path else DOCS_DIR + if not base_dir.exists(): + print(f"Error: Path not found: {base_dir}", file=sys.stderr) + sys.exit(1) + + mode_text = " (DRY RUN)" if DRY_RUN else "" + verbose_text = " (verbose)" if VERBOSE else "" + print(f"Starting conversion on {base_dir}{mode_text}{verbose_text}") + + try: + # Process images + copy_all_images() + + # Clean up any PNG/JPG files that weren't properly converted + clean_converted_pngs_in_destination() + + # Rename README files to index files (before .md to .mdx conversion) + rename_readme_to_index(base_dir) + + # Rename .md to .mdx + rename_md_to_mdx(base_dir) + + # Process all .mdx files + mdx_files = list(base_dir.rglob("*.mdx")) + if not mdx_files: + print("No MDX files found to process", file=sys.stderr) + sys.exit(1) + + log_verbose(f"Found {len(mdx_files)} MDX files to process") + + for file_path in mdx_files: + process_file(file_path) + + print_summary() + + except KeyboardInterrupt: + print("\nOperation cancelled by user", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"Unexpected error: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/docs/tools/generate-sidebars.js b/docs/tools/generate-sidebars.js new file mode 100644 index 00000000..2fefd72f --- /dev/null +++ b/docs/tools/generate-sidebars.js @@ -0,0 +1,246 @@ +#!/usr/bin/env node +// scripts/generate-sidebars.js + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Get the project root (parent of tools directory) +const projectRoot = path.resolve(__dirname, '..'); +const docsRoot = path.join(projectRoot, 'src', 'content', 'docs'); + +console.log('šŸš€ Starting sidebar generation script...'); +console.log('šŸ“ Project root:', projectRoot); +console.log('šŸ“ Docs root:', docsRoot); +console.log('šŸ” Checking if docs root exists:', fs.existsSync(docsRoot)); + +// Format label from file/folder name +function formatLabel(name) { + const withoutExt = name.replace(/\.(md|mdx)$/, ''); + const withSpaces = withoutExt.replace(/[-_]/g, ' '); + return withSpaces + .split(' ') + .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(' '); +} + +// Generate sidebar from directory structure +function generateSidebarFromDirectory(dirPath, basePath = '') { + const items = []; + + console.log(`šŸ“‚ Processing directory: ${dirPath}`); + console.log(` Base path: ${basePath}`); + + try { + const entries = fs.readdirSync(dirPath, { withFileTypes: true }); + console.log(` Found ${entries.length} entries`); + + // Sort entries: directories first, then files + entries.sort((a, b) => { + if (a.isDirectory() && !b.isDirectory()) return -1; + if (!a.isDirectory() && b.isDirectory()) return 1; + return a.name.localeCompare(b.name); + }); + + for (const entry of entries) { + console.log(` - ${entry.name} (${entry.isDirectory() ? 'dir' : 'file'})`); + + // Skip hidden files, images, sidebar.json, and non-content files + if (entry.name.startsWith('.') || + entry.name === 'sidebar.json' || + /\.(png|jpg|jpeg|gif|svg|webp)$/i.test(entry.name)) { + console.log(` ↳ Skipped (${entry.name})`); + continue; + } + + const fullPath = path.join(dirPath, entry.name); + const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name; + + if (entry.isDirectory()) { + // Check if directory has content + const subItems = generateSidebarFromDirectory(fullPath, relativePath); + if (subItems.length > 0) { + console.log(` ↳ Added directory with ${subItems.length} items`); + items.push({ + label: formatLabel(entry.name), + items: subItems, + collapsed: true + }); + } else { + console.log(` ↳ Skipped empty directory`); + } + } else if (/\.(md|mdx)$/i.test(entry.name)) { + // Handle index files as parent link + if (entry.name.toLowerCase() === 'index.md' || entry.name.toLowerCase() === 'index.mdx') { + // Add as first item with special handling + console.log(` ↳ Added overview (index file)`); + items.unshift({ + label: 'Overview', + link: `/${basePath.toLowerCase()}` + }); + } else { + console.log(` ↳ Added page: ${entry.name}`); + items.push({ + label: formatLabel(entry.name), + link: `/${relativePath.replace(/\.(md|mdx)$/, '').toLowerCase()}` + }); + } + } else { + console.log(` ↳ Skipped (not .md/.mdx)`); + } + } + } catch (error) { + console.error(`āŒ Error generating sidebar for ${dirPath}:`, error); + } + + console.log(` Generated ${items.length} items for ${dirPath}`); + return items; +} + +// Find all directories that should have sidebars +function findSidebarDirectories(dir, accumulated = []) { + console.log(`šŸ” Scanning directory: ${dir}`); + + if (!fs.existsSync(dir)) { + console.log(` Directory doesn't exist: ${dir}`); + return accumulated; + } + + const entries = fs.readdirSync(dir, { withFileTypes: true }); + console.log(` Found ${entries.length} entries in ${dir}`); + + // Check if this directory has MDX content + const hasMdxContent = entries.some(e => !e.isDirectory() && /\.(md|mdx)$/i.test(e.name)); + console.log(` Has MDX content: ${hasMdxContent}`); + + if (hasMdxContent) { + console.log(` āœ… Added to sidebar directories: ${dir}`); + accumulated.push(dir); + } + + // Look for version patterns to determine where to place sidebars + for (const entry of entries) { + if (entry.isDirectory()) { + const fullPath = path.join(dir, entry.name); + + // Skip hidden directories + if (entry.name.startsWith('.')) { + console.log(` Skipping hidden directory: ${entry.name}`); + continue; + } + + // Check if this is a version directory + const isVersionDir = /^v?\d+\.\d+/.test(entry.name); + console.log(` Directory ${entry.name} is version dir: ${isVersionDir}`); + + if (isVersionDir) { + // For version directories, each should have its own sidebar + console.log(` āœ… Added version directory: ${fullPath}`); + accumulated.push(fullPath); + } else { + // Recursively check subdirectories + findSidebarDirectories(fullPath, accumulated); + } + } + } + + return accumulated; +} + +// Generate sidebar.json files +function generateSidebars() { + console.log('šŸ” Scanning for directories that need sidebars...\n'); + + // First, check if the docs root exists + if (!fs.existsSync(docsRoot)) { + console.error(`āŒ Docs root directory doesn't exist: ${docsRoot}`); + console.log('šŸ’” Make sure you\'re running this from the project root directory'); + return; + } + + const directories = findSidebarDirectories(docsRoot); + console.log(`\nšŸ“Š Found ${directories.length} directories that need sidebars:`); + directories.forEach((dir, index) => { + console.log(` ${index + 1}. ${path.relative(docsRoot, dir)}`); + }); + + if (directories.length === 0) { + console.log('āš ļø No directories found that need sidebars. This could mean:'); + console.log(' - No .md/.mdx files found in any subdirectories'); + console.log(' - All directories already have sidebar.json files'); + console.log(' - The docs structure is different than expected'); + return; + } + + console.log('\nšŸ› ļø Processing directories...\n'); + + let generated = 0; + let skipped = 0; + let errors = 0; + + directories.forEach(dir => { + const sidebarPath = path.join(dir, 'sidebar.json'); + const relativeDir = path.relative(docsRoot, dir); + + console.log(`šŸ“ Processing: ${relativeDir}`); + + // Skip if sidebar.json already exists + if (fs.existsSync(sidebarPath)) { + console.log(` āœ“ Sidebar already exists: ${path.relative(docsRoot, sidebarPath)}`); + skipped++; + return; + } + + try { + // Generate sidebar content + const relativePath = path.relative(docsRoot, dir); + const sidebar = generateSidebarFromDirectory(dir, relativePath); + + if (sidebar.length > 0) { + // Write sidebar.json + fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2)); + console.log(` āœ… Generated sidebar: ${path.relative(docsRoot, sidebarPath)}`); + console.log(` šŸ“„ Found ${sidebar.length} top-level items`); + generated++; + } else { + console.log(` āš ļø No content found in: ${relativeDir}`); + skipped++; + } + } catch (error) { + console.error(` āŒ Error processing ${relativeDir}:`, error.message); + errors++; + } + }); + + console.log('\nāœ… Sidebar generation complete!'); + console.log(`šŸ“Š Summary:`); + console.log(` Generated: ${generated} sidebars`); + console.log(` Skipped: ${skipped} directories`); + console.log(` Errors: ${errors} failures`); + + if (generated > 0) { + console.log('\nšŸ’” You can now customize the generated sidebar.json files as needed.'); + console.log('The sidebars support:'); + console.log(' - Custom labels and ordering'); + console.log(' - Collapsed/expanded sections'); + console.log(' - Autogenerate directives for dynamic content'); + } +} + +// Add error handling for the main execution +try { + generateSidebars(); +} catch (error) { + console.error('šŸ’„ Fatal error:', error); + process.exit(1); +} + +// Run the script only if this file is executed directly +if (import.meta.url === `file://${__filename}`) { + console.log('šŸŽÆ Script executed directly'); +} else { + console.log('šŸ“¦ Script imported as module'); +} \ No newline at end of file diff --git a/docs/tools/repos-config.json b/docs/tools/repos-config.json new file mode 100644 index 00000000..1d6f5d7c --- /dev/null +++ b/docs/tools/repos-config.json @@ -0,0 +1,201 @@ +[ + { + "id": "cloud", + "group": "cloud", + "basePath": "cloud", + "docsRelativePath": ["docs", "cloud"], + "includeVersionInPath": false, + "currentBranch": "main", + "repo": "https://github.com/kurrent-io/cloud-docs", + "branches": [ + { + "version": "main", + "name": "main" + } + ] + }, + + { + "id": "getting-started", + "group": "getting-started", + "basePath": "getting-started", + "docsRelativePath": ["docs"], + "includeVersionInPath": false, + "currentBranch": "main", + "repo": "https://github.com/kurrent-io/getting-started-docs", + "branches": [ + { + "version": "main", + "name": "main" + } + ] + }, + { + "id": "client", + "group": "client", + "basePath": "client", + "docsRelativePath": ["docs", "clients"], + "includeVersionInPath": false, + "currentBranch": "main", + "repo": "https://github.com/kurrent-io/client-docs", + "branches": [ + { + "version": "main", + "name": "main" + } + ] + }, + { + "id": "tutorials", + "group": "tutorials", + "basePath": "tutorials", + "docsRelativePath": ["docs","tutorials"], + "includeVersionInPath": false, + "currentBranch": "main", + "repo": "https://github.com/kurrent-io/tutorial-docs", + "branches": [ + { + "version": "main", + "name": "main" + } + ] + }, + { + "id": "server", + "group": "Server", + "basePath": "server", + "docsRelativePath": ["docs"], + "samplesRelativePath": ["samples", "server"], + "currentBranch": "master", + "repo": "https://github.com/kurrent-io/KurrentDB", + "branches": [ + { + "version": "v25.0", + "name": "release/v25.0", + "relativePath": ["server"], + "startPage": "quick-start/" + }, + { + "version": "v24.10", + "name": "release/v24.10", + "relativePath": ["server"], + "startPage": "quick-start/" + }, + { + "version": "v24.6", + "name": "release/oss-v24.6", + "relativePath": ["server"], + "startPage": "quick-start/", + "deprecated": true, + "hide": false + }, + { + "version": "v23.10", + "name": "release/oss-v23.10", + "relativePath": ["server"], + "startPage": "quick-start/" + }, + { + "version": "v22.10", + "name": "release/oss-v22.10", + "relativePath": ["server"], + "startPage": "introduction.html" + }, + { + "version": "v5", + "name": "release/oss-v5", + "relativePath": ["server"], + "startPage": "introduction.html", + "deprecated": true, + "hide": false + } + ] + }, + + { + "id": "dotnet-client", + "group": ".NET SDK", + "basePath": "clients/dotnet", + "samplesRelativePath": ["samples"], + "repo": "https://github.com/kurrent-io/KurrentDB-Client-Dotnet", + "branches": [ + { + "version": "23.3.8", + "name": "release/v23" + } + ] + }, + { + "id": "java-client", + "group": "Java SDK", + "basePath": "clients/java", + "samplesRelativePath": [ + "src", + "test", + "java", + "io", + "kurrent", + "dbclient", + "samples" + ], + "repo": "https://github.com/kurrent-io/KurrentDB-Client-Java", + "branches": [ + { + "version": "5.4.5", + "name": "trunk" + } + ] + }, + { + "id": "rust-client", + "group": "Rust SDK", + "basePath": "clients/rust", + "samplesRelativePath": ["examples"], + "repo": "https://github.com/kurrent-io/KurrentDB-Client-Rust", + "branches": [ + { + "version": "4.0.1", + "name": "master" + } + ] + }, + { + "id": "node-client", + "group": "NodeJS SDK", + "basePath": "clients/node", + "samplesRelativePath": ["packages", "test", "src", "samples"], + "repo": "https://github.com/kurrent-io/KurrentDB-Client-NodeJS", + "branches": [ + { + "version": "6.2.1", + "name": "master" + } + ] + }, + { + "id": "go-client", + "group": "Go SDK", + "basePath": "clients/go", + "samplesRelativePath": ["samples"], + "repo": "https://github.com/kurrent-io/KurrentDB-Client-Go", + "branches": [ + { + "version": "1.0.0", + "name": "main" + } + ] + }, + { + "id": "python-client", + "group": "Python SDK", + "basePath": "clients/python", + "samplesRelativePath": ["samples"], + "repo": "https://github.com/pyeventsourcing/kurrentdbclient", + "branches": [ + { + "version": "1.0.17", + "name": "1.0" + } + ] + } +] diff --git a/docs/tools/requirements.txt b/docs/tools/requirements.txt new file mode 100644 index 00000000..b63c5751 --- /dev/null +++ b/docs/tools/requirements.txt @@ -0,0 +1 @@ +Pillow>=9.5.0 diff --git a/docs/tools/sync-repos.js b/docs/tools/sync-repos.js new file mode 100644 index 00000000..8f25c62c --- /dev/null +++ b/docs/tools/sync-repos.js @@ -0,0 +1,256 @@ +#!/usr/bin/env node + +import { spawn } from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Load configuration +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const projectRoot = path.resolve(__dirname, '..'); +const configPath = path.join(__dirname, 'repos-config.json'); + +// Check if config file exists +if (!fs.existsSync(configPath)) { + console.error(`Configuration file not found: ${configPath}`); + process.exit(1); +} + +let config; +try { + config = JSON.parse(fs.readFileSync(configPath, 'utf8')); +} catch (error) { + console.error(`Error reading configuration file: ${error.message}`); + process.exit(1); +} + +// Run a git command asynchronously with better error handling +function runGitAsync(args, cwd) { + return new Promise((resolve, reject) => { + const cp = spawn('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] }); + + let stdout = ''; + let stderr = ''; + + cp.stdout?.on('data', (data) => { + stdout += data.toString(); + }); + + cp.stderr?.on('data', (data) => { + stderr += data.toString(); + }); + + cp.on('error', err => { + console.error(`Git command failed: git ${args.join(' ')}`); + console.error(`Error: ${err.message}`); + reject(err); + }); + + cp.on('exit', code => { + if (code === 0) { + resolve(); + } else { + console.error(`Git command failed: git ${args.join(' ')}`); + if (stderr) { + console.error(`Git error output: ${stderr.trim()}`); + + // Provide helpful error messages for common issues + if (stderr.includes('Authentication failed') || stderr.includes('Permission denied')) { + console.error('\nšŸ” Authentication Error:'); + console.error('This appears to be a private repository. Try one of these solutions:'); + console.error('1. Use SSH URL instead: git@github.com:owner/repo.git'); + console.error('2. Set up GitHub CLI: gh auth login'); + console.error('3. Use a Personal Access Token in the URL'); + console.error('4. Make sure your SSH keys are properly configured'); + } + + if (stderr.includes('Repository not found')) { + console.error('\nāŒ Repository Error:'); + console.error('The repository was not found. Check:'); + console.error('1. The repository URL is correct'); + console.error('2. You have access to the repository'); + console.error('3. The repository exists and is not private (or you have proper auth)'); + } + } + reject(new Error(`git ${args.join(' ')} exited with code ${code}`)); + } + }); + }); +} + +async function cloneSubPath(repoUrl, branchName, subPath, destDir, entryId, version) { + const tempDir = path.join(projectRoot, '.tmp', entryId, version, subPath.replace(/[\\/]+/g, '_')); + + try { + // Prepare directories + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + if (fs.existsSync(destDir)) { + fs.rmSync(destDir, { recursive: true, force: true }); + } + fs.mkdirSync(tempDir, { recursive: true }); + + console.log(`Cloning ${entryId}@${version}:${subPath}`); + + // Clone with sparse checkout + await runGitAsync(['clone', '--depth', '1', '--branch', branchName, '--filter=blob:none', '--sparse', repoUrl, tempDir], projectRoot); + await runGitAsync(['sparse-checkout', 'init', '--cone'], tempDir); + await runGitAsync(['sparse-checkout', 'set', subPath], tempDir); + + // Check if subPath exists in the cloned repository + const sourcePath = path.join(tempDir, subPath); + if (!fs.existsSync(sourcePath)) { + throw new Error(`Subpath '${subPath}' not found in repository ${repoUrl} on branch ${branchName}`); + } + + // Copy only the subPath contents + fs.mkdirSync(destDir, { recursive: true }); + + // Check if there's a nested folder with the same name as entryId that we should extract from + const nestedPath = path.join(sourcePath, entryId); + const finalSourcePath = fs.existsSync(nestedPath) ? nestedPath : sourcePath; + + fs.cpSync(finalSourcePath, destDir, { recursive: true }); + + console.log(`āœ“ Completed ${entryId}@${version}:${subPath}`); + } catch (error) { + console.error(`āœ— Failed to clone ${entryId}@${version}:${subPath} - ${error.message}`); + throw error; + } finally { + // Clean up temp directory even if there was an error + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + } +} + +async function main() { + console.log('Starting repository synchronization...'); + + const operations = []; + let totalOperations = 0; + + // Build list of all operations to perform + for (const entry of config) { + const repoUrl = entry.repo; + + if (!repoUrl) { + console.error(`Missing repo URL for entry: ${entry.id || 'unknown'}`); + continue; + } + + for (const branch of entry.branches) { + const version = branch.version; + const branchName = branch.name; + const entryId = entry.id; + + if (!version || !branchName || !entryId) { + console.error(`Missing required fields for entry: ${JSON.stringify(branch)}`); + continue; + } + + const basePath = entry.basePath || entry.id || 'default'; + + // Add docs operation + if (entry.docsRelativePath) { + const subPath = entry.docsRelativePath.join('/').replace(/\\/g, '/'); + + // Only include version in path if entry.includeVersionInPath is not false + const includeVersion = entry.includeVersionInPath !== false; + const docsDest = includeVersion + ? path.join(projectRoot, 'src', 'content', 'docs', basePath, version) + : path.join(projectRoot, 'src', 'content', 'docs', basePath); + + operations.push({ + type: 'docs', + repoUrl, + branchName, + subPath, + destDir: docsDest, + entryId, + version + }); + totalOperations++; + } + + // Add samples operation + if (entry.samplesRelativePath) { + const subPath = entry.samplesRelativePath.join('/').replace(/\\/g, '/'); + + // Only include version in path if entry.includeVersionInPath is not false + const includeVersion = entry.includeVersionInPath !== false; + const samplesDest = includeVersion + ? path.join(projectRoot, 'src', 'content', '_samples', basePath, version) + : path.join(projectRoot, 'src', 'content', '_samples', basePath); + + operations.push({ + type: 'samples', + repoUrl, + branchName, + subPath, + destDir: samplesDest, + entryId, + version + }); + totalOperations++; + } + } + } + + console.log(`Total operations to perform: ${totalOperations}`); + + // Execute all operations in parallel + const results = await Promise.allSettled( + operations.map(async (op) => { + try { + await cloneSubPath(op.repoUrl, op.branchName, op.subPath, op.destDir, op.entryId, op.version); + return { success: true, operation: op }; + } catch (error) { + console.error(`Failed to sync ${op.type} for ${op.entryId}@${op.version}: ${error.message}`); + return { success: false, operation: op, error }; + } + }) + ); + + // Count results + const completedOperations = results.filter(r => r.status === 'fulfilled' && r.value.success).length; + const failedOperations = results.filter(r => r.status === 'rejected' || (r.status === 'fulfilled' && !r.value.success)).length; + + console.log('\nSynchronization complete!'); + console.log(`āœ“ Completed: ${completedOperations}`); + console.log(`āœ— Failed: ${failedOperations}`); + console.log(`šŸ“Š Total: ${totalOperations}`); + + // Show failed operations details + if (failedOperations > 0) { + console.log('\nFailed operations:'); + results.forEach(result => { + if (result.status === 'rejected') { + console.log(`āŒ ${result.reason.message}`); + } else if (result.status === 'fulfilled' && !result.value.success) { + const op = result.value.operation; + console.log(`āŒ ${op.entryId}@${op.version} (${op.type})`); + } + }); + + process.exit(1); + } +} + +// Handle process termination gracefully +process.on('SIGINT', () => { + console.log('\nOperation cancelled by user'); + process.exit(0); +}); + +process.on('SIGTERM', () => { + console.log('\nOperation terminated'); + process.exit(0); +}); + +main().catch(err => { + console.error('Fatal error:', err.message); + process.exit(1); +}); \ No newline at end of file diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 00000000..8bf91d3b --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +}