diff --git a/404.html b/404.html index a124abf068..c8cadc86fa 100644 --- a/404.html +++ b/404.html @@ -4,15 +4,15 @@ The Home of Redis Developers - - + +
-
Skip to main content
- - +
Skip to main content
+ + \ No newline at end of file diff --git a/assets/images/01-dashboard-30dbf86a0b22aeecd106670087599066.png b/assets/images/01-dashboard-30dbf86a0b22aeecd106670087599066.png deleted file mode 100644 index fc1de1bff1..0000000000 Binary files a/assets/images/01-dashboard-30dbf86a0b22aeecd106670087599066.png and /dev/null differ diff --git a/assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png b/assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png new file mode 100644 index 0000000000..46ea83abb6 Binary files /dev/null and b/assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png differ diff --git a/assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png b/assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png new file mode 100644 index 0000000000..82907b0fd4 Binary files /dev/null and b/assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png differ diff --git a/assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png b/assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png new file mode 100644 index 0000000000..6e0bc20e13 Binary files /dev/null and b/assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png differ diff --git a/assets/images/01-ui-settings-8d7e67983fe497e10e32ae9d596f3433.png b/assets/images/01-ui-settings-8d7e67983fe497e10e32ae9d596f3433.png new file mode 100644 index 0000000000..e8460e19d8 Binary files /dev/null and b/assets/images/01-ui-settings-8d7e67983fe497e10e32ae9d596f3433.png differ diff --git a/assets/images/01-ui-settings2-6ee14e85462dccc0cf3bfe463076c403.png b/assets/images/01-ui-settings2-6ee14e85462dccc0cf3bfe463076c403.png new file mode 100644 index 0000000000..927cbe1933 Binary files /dev/null and b/assets/images/01-ui-settings2-6ee14e85462dccc0cf3bfe463076c403.png differ diff --git a/assets/images/02-ai-bot-c7989293733f79cedcc9f475171c9b03.png b/assets/images/02-ai-bot-c7989293733f79cedcc9f475171c9b03.png deleted file mode 100644 index 3bbd549687..0000000000 Binary files a/assets/images/02-ai-bot-c7989293733f79cedcc9f475171c9b03.png and /dev/null differ diff --git a/assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png b/assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png new file mode 100644 index 0000000000..d5fb913aa0 Binary files /dev/null and b/assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png differ diff --git a/assets/images/02-ui-image-search-770befcd5c2129a025fc5fe9058d286f.png b/assets/images/02-ui-image-search-770befcd5c2129a025fc5fe9058d286f.png new file mode 100644 index 0000000000..82907b0fd4 Binary files /dev/null and b/assets/images/02-ui-image-search-770befcd5c2129a025fc5fe9058d286f.png differ diff --git a/assets/images/02-ui-image-search2-e92f1bb2c539726c3125969a90d5a5d0.png b/assets/images/02-ui-image-search2-e92f1bb2c539726c3125969a90d5a5d0.png new file mode 100644 index 0000000000..6e0bc20e13 Binary files /dev/null and b/assets/images/02-ui-image-search2-e92f1bb2c539726c3125969a90d5a5d0.png differ diff --git a/assets/images/03-ui-toggle-image-summary-2f6a1e8369101b7ee64861cb94599a1c.jpg b/assets/images/03-ui-toggle-image-summary-2f6a1e8369101b7ee64861cb94599a1c.jpg new file mode 100644 index 0000000000..84a384e42e Binary files /dev/null and b/assets/images/03-ui-toggle-image-summary-2f6a1e8369101b7ee64861cb94599a1c.jpg differ diff --git a/assets/images/04-shopping-cart-5445685389780e76ba7135e47f0ad20b.png b/assets/images/04-ai-product-shopping-cart-5445685389780e76ba7135e47f0ad20b.png similarity index 100% rename from assets/images/04-shopping-cart-5445685389780e76ba7135e47f0ad20b.png rename to assets/images/04-ai-product-shopping-cart-5445685389780e76ba7135e47f0ad20b.png diff --git a/assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png b/assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png new file mode 100644 index 0000000000..56a4496f09 Binary files /dev/null and b/assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png differ diff --git a/assets/images/product-img-741e131fef5eb5774118950873e3a5da.webp b/assets/images/product-img-741e131fef5eb5774118950873e3a5da.webp new file mode 100644 index 0000000000..5c2de3f149 Binary files /dev/null and b/assets/images/product-img-741e131fef5eb5774118950873e3a5da.webp differ diff --git a/assets/images/redis-insight-ai-image-6cc94b6b258688ef091048bd8933f99e.png b/assets/images/redis-insight-ai-image-6cc94b6b258688ef091048bd8933f99e.png new file mode 100644 index 0000000000..c665bbb6d3 Binary files /dev/null and b/assets/images/redis-insight-ai-image-6cc94b6b258688ef091048bd8933f99e.png differ diff --git a/assets/images/redis-insight-ai-product-details-a96b09c9e51a5d23cab2a3140e6cf4d5.png b/assets/images/redis-insight-ai-product-details-a96b09c9e51a5d23cab2a3140e6cf4d5.png new file mode 100644 index 0000000000..51cd041a39 Binary files /dev/null and b/assets/images/redis-insight-ai-product-details-a96b09c9e51a5d23cab2a3140e6cf4d5.png differ diff --git a/assets/js/28193d1c.0dd80e8b.js b/assets/js/28193d1c.0dd80e8b.js deleted file mode 100644 index 06a1195956..0000000000 --- a/assets/js/28193d1c.0dd80e8b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[3482],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>h});var o=r(67294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=o.createContext({}),p=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},m=function(e){var t=p(e.components);return o.createElement(c.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},l=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),l=p(r),h=n,u=l["".concat(c,".").concat(h)]||l[h]||d[h]||a;return r?o.createElement(u,i(i({ref:t},m),{},{components:r})):o.createElement(u,i({ref:t},m))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=l;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:n,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var o=r(87462),n=(r(67294),r(3905));const a={},i=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",id:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",title:"microservices-ecommerce-ai",description:"The e-commerce microservices application consists of a frontend, built using Next.js with TailwindCSS. The application backend uses Node.js. The data is stored in",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",tags:[],version:"current",lastUpdatedAt:1702551239,formattedLastUpdatedAt:"Dec 14, 2023",frontMatter:{}},c={},p=[],m={toc:p};function d(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,o.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The e-commerce microservices application consists of a frontend, built using ",(0,n.kt)("a",{parentName:"p",href:"https://nextjs.org/"},"Next.js")," with ",(0,n.kt)("a",{parentName:"p",href:"https://tailwindcss.com/"},"TailwindCSS"),". The application backend uses ",(0,n.kt)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js"),". The data is stored in\n",(0,n.kt)("a",{parentName:"p",href:"https://redis.com/try-free/"},"Redis")," and MongoDB/ Postgressql using ",(0,n.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"Prisma"),". Below you will find screenshots of the frontend of the e-commerce app:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("inlineCode",{parentName:"p"},"Dashboard"),": Shows the list of products with search functionality"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend products page",src:r(7050).Z,width:"1024",height:"487"}))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("inlineCode",{parentName:"p"},"Chat bot"),": The chat bot is available on the bottom right corner of the page. It can be used to search for products and view the product details."),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend chat bot",src:r(99609).Z,width:"2618",height:"1242"})),(0,n.kt)("p",{parentName:"li"},"Clicking on a product in the chat shows the product details on dashboard"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend product details",src:r(73064).Z,width:"2624",height:"1252"}))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("inlineCode",{parentName:"p"},"Shopping Cart"),': Add products to the cart, then check out using the "Buy Now" button\n',(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend shopping cart",src:r(15030).Z,width:"2624",height:"1244"}))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("inlineCode",{parentName:"p"},"Order history"),": Once an order is placed, the ",(0,n.kt)("inlineCode",{parentName:"p"},"Orders")," link in the top navigation bar shows the order status and history"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend order history page",src:r(14065).Z,width:"2609",height:"674"}))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("inlineCode",{parentName:"p"},"Admin"),": The ",(0,n.kt)("inlineCode",{parentName:"p"},"admin")," link in the top navigation bar shows purchase stats and trending products."),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend admin page",src:r(37740).Z,width:"2604",height:"1230"}),"\n",(0,n.kt)("img",{alt:"redis microservices e-commerce app frontend admin page",src:r(96127).Z,width:"2608",height:"858"})))))}d.isMDXComponent=!0},7050:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/01-dashboard-30dbf86a0b22aeecd106670087599066.png"},99609:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/02-ai-bot-c7989293733f79cedcc9f475171c9b03.png"},73064:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/03-ai-bot-product-ed8e13e4a32f72b952d683473a4c4d0f.png"},15030:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/04-shopping-cart-5445685389780e76ba7135e47f0ad20b.png"},14065:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/05-order-history-fa1ebafcf8ac4ee027f5616a00044ee9.png"},37740:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/06-admin-charts-5ae00e6182be0b4ada06049f5d18d0aa.png"},96127:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/07-admin-top-trending-941390270b22d7b4243b386af50ec743.png"}}]); \ No newline at end of file diff --git a/assets/js/28193d1c.97c50107.js b/assets/js/28193d1c.97c50107.js new file mode 100644 index 0000000000..cbf83ce865 --- /dev/null +++ b/assets/js/28193d1c.97c50107.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[3482],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>l});var s=r(67294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,s)}return r}function a(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=s.createContext({}),p=function(e){var t=s.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},d=function(e){var t=p(e.components);return s.createElement(c.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return s.createElement(s.Fragment,{},t)}},h=s.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=p(r),l=n,g=h["".concat(c,".").concat(l)]||h[l]||m[l]||o;return r?s.createElement(g,a(a({ref:t},d),{},{components:r})):s.createElement(g,a({ref:t},d))}));function l(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:n,a[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var s=r(87462),n=(r(67294),r(3905));const o={},a=void 0,i={unversionedId:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",id:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",title:"microservices-ecommerce-ai",description:"The e-commerce microservices application consists of a frontend, built using Next.js with TailwindCSS. The application backend uses Node.js. The data is stored in Redis and either MongoDB or PostgreSQL, using Prisma. Below are screenshots showcasing the frontend of the e-commerce app.",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705608576,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},p=[],d={toc:p};function m(e){let{components:t,...o}=e;return(0,n.kt)("wrapper",(0,s.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The e-commerce microservices application consists of a frontend, built using ",(0,n.kt)("a",{parentName:"p",href:"https://nextjs.org/"},"Next.js")," with ",(0,n.kt)("a",{parentName:"p",href:"https://tailwindcss.com/"},"TailwindCSS"),". The application backend uses ",(0,n.kt)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js"),". The data is stored in ",(0,n.kt)("a",{parentName:"p",href:"https://redis.com/try-free/"},"Redis")," and either MongoDB or PostgreSQL, using ",(0,n.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"Prisma"),". Below are screenshots showcasing the frontend of the e-commerce app."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Dashboard:")," Displays a list of products with different search functionalities, configurable in the settings page.\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Products Page",src:r(7050).Z,width:"2618",height:"1194"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Settings:")," Accessible by clicking the gear icon at the top right of the dashboard. Control the search bar, chatbot visibility, and other features here.\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Settings Page",src:r(8461).Z,width:"1822",height:"956"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Dashboard (Semantic Text Search):"),' Configured for semantic text search, the search bar enables natural language queries. Example: "pure cotton blue shirts."\n',(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Text Search",src:r(81168).Z,width:"1920",height:"900"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Dashboard (Semantic Image-Based Queries):"),' Configured for semantic image summary search, the search bar allows for image-based queries. Example: "Left chest nike logo."\n',(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Image Search",src:r(2680).Z,width:"2608",height:"1216"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Chat Bot:")," Located at the bottom right corner of the page, assisting in product searches and detailed views.\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Chat Bot",src:r(99609).Z,width:"1920",height:"911"})),(0,n.kt)("p",null,"Selecting a product in the chat displays its details on the dashboard.\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Product Details",src:r(73064).Z,width:"2624",height:"1252"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Shopping Cart:"),' Add products to the cart and check out using the "Buy Now" button.\n',(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Shopping Cart",src:r(12224).Z,width:"2624",height:"1244"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Order History:")," Post-purchase, the 'Orders' link in the top navigation bar shows the order status and history.\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Order History Page",src:r(14065).Z,width:"2609",height:"674"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Admin Panel:")," Accessible via the 'admin' link in the top navigation. Displays purchase statistics and trending products.\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:r(37740).Z,width:"2604",height:"1230"}),"\n",(0,n.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:r(96127).Z,width:"2608",height:"858"})))}m.isMDXComponent=!0},2680:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png"},81168:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png"},7050:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png"},99609:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png"},73064:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/03-ai-bot-product-ed8e13e4a32f72b952d683473a4c4d0f.png"},12224:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/04-ai-product-shopping-cart-5445685389780e76ba7135e47f0ad20b.png"},14065:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/05-order-history-fa1ebafcf8ac4ee027f5616a00044ee9.png"},37740:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/06-admin-charts-5ae00e6182be0b4ada06049f5d18d0aa.png"},96127:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/07-admin-top-trending-941390270b22d7b4243b386af50ec743.png"},8461:(e,t,r)=>{r.d(t,{Z:()=>s});const s=r.p+"assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png"}}]); \ No newline at end of file diff --git a/assets/js/48f88c7a.74a0f515.js b/assets/js/48f88c7a.b3c05b46.js similarity index 94% rename from assets/js/48f88c7a.74a0f515.js rename to assets/js/48f88c7a.b3c05b46.js index 54cbd32661..914b09735e 100644 --- a/assets/js/48f88c7a.74a0f515.js +++ b/assets/js/48f88c7a.b3c05b46.js @@ -1 +1 @@ -"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[7310],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var o=r(67294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var a=o.createContext({}),l=function(e){var t=o.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return o.createElement(a.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,c=e.originalType,a=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=l(r),d=n,f=m["".concat(a,".").concat(d)]||m[d]||p[d]||c;return r?o.createElement(f,i(i({ref:t},u),{},{components:r})):o.createElement(f,i({ref:t},u))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var c=r.length,i=new Array(c);i[0]=m;var s={};for(var a in t)hasOwnProperty.call(t,a)&&(s[a]=t[a]);s.originalType=e,s.mdxType="string"==typeof e?e:n,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>c,metadata:()=>s,toc:()=>l});var o=r(87462),n=(r(67294),r(3905));const c={},i=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-source-code-ai",id:"howtos/solutions/vector/common-ai/microservices-source-code-ai",title:"microservices-source-code-ai",description:"Below is a command to the clone the source code for the application used in this tutorial",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",tags:[],version:"current",lastUpdatedAt:1702667455,formattedLastUpdatedAt:"Dec 15, 2023",frontMatter:{}},a={},l=[],u={toc:l};function p(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,o.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("admonition",{title:"GITHUB CODE",type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"Below is a command to the clone the source code for the application used in this tutorial"),(0,n.kt)("p",{parentName:"admonition"},"git clone --branch v7.1.0 ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"},"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"))))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[7310],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var o=r(67294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var a=o.createContext({}),l=function(e){var t=o.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return o.createElement(a.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,c=e.originalType,a=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=l(r),d=n,f=m["".concat(a,".").concat(d)]||m[d]||p[d]||c;return r?o.createElement(f,i(i({ref:t},u),{},{components:r})):o.createElement(f,i({ref:t},u))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var c=r.length,i=new Array(c);i[0]=m;var s={};for(var a in t)hasOwnProperty.call(t,a)&&(s[a]=t[a]);s.originalType=e,s.mdxType="string"==typeof e?e:n,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>c,metadata:()=>s,toc:()=>l});var o=r(87462),n=(r(67294),r(3905));const c={},i=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-source-code-ai",id:"howtos/solutions/vector/common-ai/microservices-source-code-ai",title:"microservices-source-code-ai",description:"Below is a command to the clone the source code for the application used in this tutorial",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705611366,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},a={},l=[],u={toc:l};function p(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,o.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("admonition",{title:"GITHUB CODE",type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"Below is a command to the clone the source code for the application used in this tutorial"),(0,n.kt)("p",{parentName:"admonition"},"git clone --branch v9.2.0 ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"},"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4a2cafb1.4be949b6.js b/assets/js/4a2cafb1.4be949b6.js new file mode 100644 index 0000000000..4b17c65a9b --- /dev/null +++ b/assets/js/4a2cafb1.4be949b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[6563,4074,3482,7310],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>u});var r=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),d=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=d(e.components);return r.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),m=d(n),u=o,h=m["".concat(c,".").concat(u)]||m[u]||p[u]||a;return n?r.createElement(h,i(i({ref:t},l),{},{components:n})):r.createElement(h,i({ref:t},l))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:o,i[1]=s;for(var d=2;d{n.d(t,{Z:()=>c});var r=n(67294),o=n(52263);const a="authorByline_VoxI",i="authorLabel_a70t",s="authorProfileImage_URwT";const c=function(e){let{frontMatter:t}=e;const{siteConfig:n}=(0,o.Z)(),c=n.customFields.authors;return r.createElement(r.Fragment,null,t.authors&&r.createElement("div",{className:"docAuthors"},r.createElement("hr",null),t.authors.map((e=>r.createElement("div",{key:e,className:a},r.createElement("img",{className:s,src:`/img/${c[e].image?c[e].image:"default_author_profile_pic.png"}`,alt:`Profile picture for ${c[e].name}`}),r.createElement("div",null,r.createElement("div",{className:i},"Author:"),r.createElement("div",null,r.createElement("a",{href:c[e].link,target:"_blank"},c[e].name),", ",c[e].title))))),r.createElement("hr",null)))}},36773:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var r=n(87462),o=(n(67294),n(3905));const a={},i=void 0,s={unversionedId:"howtos/solutions/microservices/common-data/microservices-arch",id:"howtos/solutions/microservices/common-data/microservices-arch",title:"microservices-arch",description:"Lets take a look at the architecture of the demo application:",source:"@site/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",sourceDirName:"howtos/solutions/microservices/common-data",slug:"/howtos/solutions/microservices/common-data/microservices-arch",permalink:"/howtos/solutions/microservices/common-data/microservices-arch",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",tags:[],version:"current",lastUpdatedAt:1702551239,formattedLastUpdatedAt:"Dec 14, 2023",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Lets take a look at the architecture of the demo application:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"products service"),": handles querying products from the database and returning them to the frontend"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"orders service"),": handles validating and creating orders"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"order history service"),": handles querying a customer's order history"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payments service"),": handles processing orders for payment"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"api gateway"),": unifies the services under a single endpoint"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"mongodb/ postgresql"),": serves as the write-optimized database for storing orders, order history, products, etc.")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"You don't need to use MongoDB/ Postgresql as your write-optimized database in the demo application; you can use other ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"prisma supported databases"))," as well. This is just an example.")))}p.isMDXComponent=!0},80990:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var r=n(87462),o=(n(67294),n(3905));const a={},i=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",id:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",title:"microservices-ecommerce-ai",description:"The e-commerce microservices application consists of a frontend, built using Next.js with TailwindCSS. The application backend uses Node.js. The data is stored in Redis and either MongoDB or PostgreSQL, using Prisma. Below are screenshots showcasing the frontend of the e-commerce app.",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705608576,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,r.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"The e-commerce microservices application consists of a frontend, built using ",(0,o.kt)("a",{parentName:"p",href:"https://nextjs.org/"},"Next.js")," with ",(0,o.kt)("a",{parentName:"p",href:"https://tailwindcss.com/"},"TailwindCSS"),". The application backend uses ",(0,o.kt)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js"),". The data is stored in ",(0,o.kt)("a",{parentName:"p",href:"https://redis.com/try-free/"},"Redis")," and either MongoDB or PostgreSQL, using ",(0,o.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"Prisma"),". Below are screenshots showcasing the frontend of the e-commerce app."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Dashboard:")," Displays a list of products with different search functionalities, configurable in the settings page.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Products Page",src:n(7050).Z,width:"2618",height:"1194"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Settings:")," Accessible by clicking the gear icon at the top right of the dashboard. Control the search bar, chatbot visibility, and other features here.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Settings Page",src:n(8461).Z,width:"1822",height:"956"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Dashboard (Semantic Text Search):"),' Configured for semantic text search, the search bar enables natural language queries. Example: "pure cotton blue shirts."\n',(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Text Search",src:n(81168).Z,width:"1920",height:"900"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Dashboard (Semantic Image-Based Queries):"),' Configured for semantic image summary search, the search bar allows for image-based queries. Example: "Left chest nike logo."\n',(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Image Search",src:n(2680).Z,width:"2608",height:"1216"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Chat Bot:")," Located at the bottom right corner of the page, assisting in product searches and detailed views.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Chat Bot",src:n(99609).Z,width:"1920",height:"911"})),(0,o.kt)("p",null,"Selecting a product in the chat displays its details on the dashboard.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Product Details",src:n(73064).Z,width:"2624",height:"1252"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Shopping Cart:"),' Add products to the cart and check out using the "Buy Now" button.\n',(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Shopping Cart",src:n(12224).Z,width:"2624",height:"1244"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Order History:")," Post-purchase, the 'Orders' link in the top navigation bar shows the order status and history.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Order History Page",src:n(14065).Z,width:"2609",height:"674"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Admin Panel:")," Accessible via the 'admin' link in the top navigation. Displays purchase statistics and trending products.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:n(37740).Z,width:"2604",height:"1230"}),"\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:n(96127).Z,width:"2608",height:"858"})))}p.isMDXComponent=!0},10992:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var r=n(87462),o=(n(67294),n(3905));const a={},i=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-source-code-ai",id:"howtos/solutions/vector/common-ai/microservices-source-code-ai",title:"microservices-source-code-ai",description:"Below is a command to the clone the source code for the application used in this tutorial",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705611366,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("admonition",{title:"GITHUB CODE",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Below is a command to the clone the source code for the application used in this tutorial"),(0,o.kt)("p",{parentName:"admonition"},"git clone --branch v9.2.0 ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"},"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"))))}p.isMDXComponent=!0},14096:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>g,frontMatter:()=>d,metadata:()=>p,toc:()=>u});var r=n(87462),o=(n(67294),n(3905)),a=n(50358),i=n(36773),s=n(80990),c=n(10992);const d={id:"index-semantic-text-search",title:"Semantic Text Search Using LangChain (OpenAI) and Redis",sidebar_label:"Semantic Text Search Using LangChain (OpenAI) and Redis",slug:"/howtos/solutions/vector/semantic-text-search",authors:["prasan","will"]},l=void 0,p={unversionedId:"howtos/solutions/vector/semantic-text-search/index-semantic-text-search",id:"howtos/solutions/vector/semantic-text-search/index-semantic-text-search",title:"Semantic Text Search Using LangChain (OpenAI) and Redis",description:"What you will learn in this tutorial",source:"@site/docs/howtos/solutions/vector/semantic-text-search/index-semantic-text-search.mdx",sourceDirName:"howtos/solutions/vector/semantic-text-search",slug:"/howtos/solutions/vector/semantic-text-search",permalink:"/howtos/solutions/vector/semantic-text-search",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/semantic-text-search/index-semantic-text-search.mdx",tags:[],version:"current",lastUpdatedAt:1705611366,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{id:"index-semantic-text-search",title:"Semantic Text Search Using LangChain (OpenAI) and Redis",sidebar_label:"Semantic Text Search Using LangChain (OpenAI) and Redis",slug:"/howtos/solutions/vector/semantic-text-search",authors:["prasan","will"]},sidebar:"docs",previous:{title:"How to Build a GenAI Chatbot Using LangChain and Redis",permalink:"/howtos/solutions/vector/gen-ai-chatbot"},next:{title:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",permalink:"/howtos/solutions/vector/image-summary-search"}},m={},u=[{value:"What you will learn in this tutorial",id:"what-you-will-learn-in-this-tutorial",level:2},{value:"Terminology",id:"terminology",level:2},{value:"Microservices architecture for an e-commerce application",id:"microservices-architecture-for-an-e-commerce-application",level:2},{value:"E-commerce application frontend using Next.js and Tailwind",id:"e-commerce-application-frontend-using-nextjs-and-tailwind",level:2},{value:"Database setup",id:"database-setup",level:2},{value:"Sample data",id:"sample-data",level:3},{value:"Seeding product details embeddings",id:"seeding-product-details-embeddings",level:3},{value:"Setting up the search API",id:"setting-up-the-search-api",level:2},{value:"API end point",id:"api-end-point",level:3},{value:"API implementation",id:"api-implementation",level:3},{value:"Frontend UI",id:"frontend-ui",level:3},{value:"Ready to use Redis for semantic text search?",id:"ready-to-use-redis-for-semantic-text-search",level:2},{value:"Further reading",id:"further-reading",level:2}],h={toc:u};function g(e){let{components:t,...l}=e;return(0,o.kt)("wrapper",(0,r.Z)({},h,l,{components:t,mdxType:"MDXLayout"}),(0,o.kt)(a.Z,{frontMatter:d,mdxType:"Authors"}),(0,o.kt)("h2",{id:"what-you-will-learn-in-this-tutorial"},"What you will learn in this tutorial"),(0,o.kt)("p",null,"This tutorial explores the implementation of semantic text search in product descriptions using LangChain (OpenAI) and Redis. The focus areas include:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Contextualizing E-Commerce"),": Dive into an e-commerce scenario where semantic text search empowers users to find products through detailed textual queries."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Database Implementation"),": Learn to create and store semantic embeddings from product descriptions in Redis for efficient search capabilities."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Search API Development"),": Understand how to build an API that leverages OpenAI for semantic analysis of text and Redis for data management.")),(0,o.kt)("h2",{id:"terminology"},"Terminology"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},(0,o.kt)("a",{parentName:"strong",href:"https://js.langchain.com"},"LangChain")),": A versatile library for developing language model applications, combining language models, storage systems, and custom logic."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},(0,o.kt)("a",{parentName:"strong",href:"https://openai.com/"},"OpenAI")),": A provider of cutting-edge language models like GPT-3, essential for applications in semantic search and conversational AI.")),(0,o.kt)("h2",{id:"microservices-architecture-for-an-e-commerce-application"},"Microservices architecture for an e-commerce application"),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)(i.default,{mdxType:"InitialMicroservicesArchitecture"}),(0,o.kt)("h2",{id:"e-commerce-application-frontend-using-nextjs-and-tailwind"},"E-commerce application frontend using Next.js and Tailwind"),(0,o.kt)(s.default,{mdxType:"MicroservicesEcommerceAIDesign"}),(0,o.kt)("h2",{id:"database-setup"},"Database setup"),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Sign up for an ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://platform.openai.com/"},"OpenAI account"))," to get your API key to be used in the demo (add OPEN_AI_API_KEY variable in .env file). You can also refer to the ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://platform.openai.com/docs/api-reference/introduction"},"OpenAI API documentation"))," for more information.")),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)("h3",{id:"sample-data"},"Sample data"),(0,o.kt)("p",null,"Consider a simplified e-commerce dataset featuring product details for semantic search."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/fashion-dataset/001/products/*.json"',title:'"database/fashion-dataset/001/products/*.json"'},"const products = [\n {\n productId: '11000',\n price: 3995,\n productDisplayName: 'Puma Men Slick 3HD Yellow Black Watches',\n variantName: 'Slick 3HD Yellow',\n brandName: 'Puma',\n ageGroup: 'Adults-Men',\n gender: 'Men',\n displayCategories: 'Accessories',\n masterCategory_typeName: 'Accessories',\n subCategory_typeName: 'Watches',\n styleImages_default_imageURL:\n 'http://host.docker.internal:8080/images/11000.jpg',\n productDescriptors_description_value: 'Stylish and comfortable, ...',\n stockQty: 25,\n },\n //...\n];\n")),(0,o.kt)("h3",{id:"seeding-product-details-embeddings"},"Seeding product details embeddings"),(0,o.kt)("p",null,"Implement the ",(0,o.kt)("inlineCode",{parentName:"p"},"addEmbeddingsToRedis")," function to integrate AI-generated product description embeddings with Redis."),(0,o.kt)("p",null,"This process involves two main steps:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Generating Vector Documents"),": Utilizing the ",(0,o.kt)("inlineCode",{parentName:"p"},"convertToVectorDocuments")," function, we transform product details into vector documents. This transformation is crucial as it converts product details into a format suitable for Redis storage.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Seeding Embeddings into Redis"),": The ",(0,o.kt)("inlineCode",{parentName:"p"},"seedOpenAIEmbeddings")," function is then employed to store these vector documents into Redis. This step is essential for enabling efficient retrieval and search capabilities within the Redis database."))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},"import { Document } from 'langchain/document';\nimport { OpenAIEmbeddings } from 'langchain/embeddings/openai';\nimport { RedisVectorStore } from 'langchain/vectorstores/redis';\n\nconst convertToVectorDocuments = async (\n _products: Prisma.ProductCreateInput[],\n) => {\n const vectorDocs: Document[] = [];\n\n if (_products?.length > 0) {\n for (let product of _products) {\n let doc = new Document({\n metadata: {\n productId: product.productId,\n },\n pageContent: ` Product details are as follows:\n productId: ${product.productId}.\n \n productDisplayName: ${product.productDisplayName}.\n \n price: ${product.price}.\n \n variantName: ${product.variantName}.\n \n brandName: ${product.brandName}.\n \n ageGroup: ${product.ageGroup}.\n \n gender: ${product.gender}.\n \n productColors: ${product.productColors}\n \n Category: ${product.displayCategories}, ${product.masterCategory_typeName} - ${product.subCategory_typeName}\n \n productDescription: ${product.productDescriptors_description_value}`,\n });\n\n vectorDocs.push(doc);\n }\n }\n return vectorDocs;\n};\n\nconst seedOpenAIEmbeddings = async (\n vectorDocs: Document[],\n _redisClient: NodeRedisClientType,\n _openAIApiKey: string,\n) => {\n if (vectorDocs?.length && _redisClient && _openAIApiKey) {\n console.log('openAIEmbeddings started !');\n\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: _openAIApiKey,\n });\n const vectorStore = await RedisVectorStore.fromDocuments(\n vectorDocs,\n embeddings,\n {\n redisClient: _redisClient,\n indexName: 'openAIProductsIdx',\n keyPrefix: 'openAIProducts:',\n },\n );\n console.log('OpenAIEmbeddings completed');\n }\n};\n\nconst addEmbeddingsToRedis = async (\n _products: Prisma.ProductCreateInput[],\n _redisClient: NodeRedisClientType,\n _openAIApiKey: string,\n _huggingFaceApiKey?: string,\n) => {\n if (_products?.length > 0 && _redisClient && _openAIApiKey) {\n const vectorDocs = await convertToVectorDocuments(_products);\n\n await seedOpenAIEmbeddings(vectorDocs, _redisClient, _openAIApiKey);\n }\n};\n")),(0,o.kt)("p",null,"Examine the structured ",(0,o.kt)("inlineCode",{parentName:"p"},"openAI product details")," within Redis using RedisInsight."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight AI products",src:n(94221).Z,width:"2320",height:"1424"})),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Download ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://redis.com/redis-enterprise/redis-insight/"},"RedisInsight"))," to visually explore your Redis data or to engage with raw Redis commands in the workbench.")),(0,o.kt)("h2",{id:"setting-up-the-search-api"},"Setting up the search API"),(0,o.kt)("h3",{id:"api-end-point"},"API end point"),(0,o.kt)("p",null,"This section covers the API request and response structure for ",(0,o.kt)("inlineCode",{parentName:"p"},"getProductsByVSSText"),", which is essential for retrieving products based on semantic text search."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request Format")),(0,o.kt)("p",null,"The example request format for the API is as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'POST http://localhost:3000/products/getProductsByVSSText\n{\n "searchText":"pure cotton blue shirts",\n\n //optional\n "maxProductCount": 4, // 2 (default)\n "similarityScoreLimit":0.2, // 0.2 (default)\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Response Structure")),(0,o.kt)("p",null,"The response from the API is a JSON object containing an array of product details that match the semantic search criteria:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "data": [\n {\n "productId": "11031",\n "price": 1099,\n "productDisplayName": "Jealous 21 Women Check Blue Tops",\n "productDescriptors_description_value": "Composition : Green and navy blue checked round neck blouson tunic top made of 100% cotton, has a full buttoned placket, three fourth sleeves with buttoned cuffs and a belt below the waist

Fitting
Regular

Wash care
Machine/hand wash separately in mild detergent
Do not bleach or wring
Dry in shade
Medium iron

If you\'re in the mood to have some checked fun, this blouson tunic top from jealous 21 will fulfil your heart\'s desire with élan. The cotton fabric promises comfort, while the smart checks guarantee unparalleled attention. Pair this top with leggings and ballerinas for a cute, neat look.

Model statistics
The model wears size M in tops
Height: 5\'7\\"; Chest: 33\\"; Waist: 25\\"

",\n "stockQty": 25,\n "productColors": "Blue,Green",\n "similarityScore": 0.168704152107\n //...\n }\n ],\n "error": null,\n "auth": "SES_fd57d7f4-3deb-418f-9a95-6749cd06e348"\n}\n')),(0,o.kt)("h3",{id:"api-implementation"},"API implementation"),(0,o.kt)("p",null,"The backend implementation of this API involves following steps:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"getProductsByVSSText")," function handles the API Request."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"getSimilarProductsScoreByVSS")," function performs semantic search on product details. It integrates with ",(0,o.kt)("inlineCode",{parentName:"li"},"OpenAI's")," semantic analysis capabilities to interpret the searchText and identify relevant products from ",(0,o.kt)("inlineCode",{parentName:"li"},"Redis")," vector store.")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"const getSimilarProductsScoreByVSS = async (\n _params: IParamsGetProductsByVSS,\n) => {\n let {\n standAloneQuestion,\n openAIApiKey,\n\n //optional\n KNN,\n scoreLimit,\n } = _params;\n\n let vectorDocs: Document[] = [];\n const client = getNodeRedisClient();\n\n KNN = KNN || 2;\n scoreLimit = scoreLimit || 1;\n\n let embeddings = new OpenAIEmbeddings({\n openAIApiKey: openAIApiKey,\n });\n let indexName = 'openAIProductsIdx';\n let keyPrefix = 'openAIProducts:';\n\n if (embeddings) {\n // create vector store\n const vectorStore = new RedisVectorStore(embeddings, {\n redisClient: client,\n indexName: indexName,\n keyPrefix: keyPrefix,\n });\n\n // search for similar products\n const vectorDocsWithScore = await vectorStore.similaritySearchWithScore(\n standAloneQuestion,\n KNN,\n );\n\n // filter by scoreLimit\n for (let [doc, score] of vectorDocsWithScore) {\n if (score <= scoreLimit) {\n doc['similarityScore'] = score;\n vectorDocs.push(doc);\n }\n }\n }\n\n return vectorDocs;\n};\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/service-impl.ts"',title:'"server/src/services/products/src/service-impl.ts"'},"const getProductsByVSSText = async (\n productsVSSFilter: IProductsVSSBodyFilter,\n) => {\n let { searchText, maxProductCount, similarityScoreLimit } = productsVSSFilter;\n let products: IProduct[] = [];\n\n const openAIApiKey = process.env.OPEN_AI_API_KEY || '';\n maxProductCount = maxProductCount || 2;\n similarityScoreLimit = similarityScoreLimit || 0.2;\n\n if (!openAIApiKey) {\n throw new Error('Please provide openAI API key in .env file');\n }\n\n if (!searchText) {\n throw new Error('Please provide search text');\n }\n\n //VSS search\n const vectorDocs = await getSimilarProductsScoreByVSS({\n standAloneQuestion: searchText,\n openAIApiKey: openAIApiKey,\n KNN: maxProductCount,\n scoreLimit: similarityScoreLimit,\n });\n\n if (vectorDocs?.length) {\n const productIds = vectorDocs.map((doc) => doc?.metadata?.productId);\n\n //get product with details\n products = await getProductByIds(productIds, true);\n }\n\n //...\n\n return products;\n};\n")),(0,o.kt)("h3",{id:"frontend-ui"},"Frontend UI"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Settings configuration"),": Enable ",(0,o.kt)("inlineCode",{parentName:"p"},"Semantic text search")," in the settings page\n",(0,o.kt)("img",{alt:"settings page",src:n(64254).Z,width:"1826",height:"1206"}))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Performing a search"),": Use textual queries on the dashboard.\n",(0,o.kt)("img",{alt:"search page",src:n(44320).Z,width:"1920",height:"900"}))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("i",null,"Note:")," Users can click on the product description within the product card to view the complete details.")),(0,o.kt)("h2",{id:"ready-to-use-redis-for-semantic-text-search"},"Ready to use Redis for semantic text search?"),(0,o.kt)("p",null,"Discover the power of semantic text search for enhancing the e-commerce experience. This tutorial guides you through integrating OpenAI's semantic capabilities with Redis for a dynamic product search engine."),(0,o.kt)("h2",{id:"further-reading"},"Further reading"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"/howtos/solutions/vector/getting-started-vector"},"Perform vector similarity search using Redis"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"/howtos/solutions/vector/image-summary-search"},"Semantic Image Based Queries Using LangChain (OpenAI) and Redis"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/get_started/quickstart"},"LangChain JS")),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://scrimba.com/learn/langchain"},"Learn LangChain")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/integrations/vectorstores/redis"},"LangChain redis integration")))))}g.isMDXComponent=!0},2680:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png"},81168:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png"},7050:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png"},99609:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png"},73064:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/03-ai-bot-product-ed8e13e4a32f72b952d683473a4c4d0f.png"},12224:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/04-ai-product-shopping-cart-5445685389780e76ba7135e47f0ad20b.png"},14065:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/05-order-history-fa1ebafcf8ac4ee027f5616a00044ee9.png"},37740:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/06-admin-charts-5ae00e6182be0b4ada06049f5d18d0aa.png"},96127:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/07-admin-top-trending-941390270b22d7b4243b386af50ec743.png"},8461:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png"},64254:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/01-ui-settings2-6ee14e85462dccc0cf3bfe463076c403.png"},44320:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/02-ui-image-search2-e92f1bb2c539726c3125969a90d5a5d0.png"},94221:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/redis-insight-ai-product-details-a96b09c9e51a5d23cab2a3140e6cf4d5.png"}}]); \ No newline at end of file diff --git a/assets/js/5ea22235.3f9844ed.js b/assets/js/5ea22235.3f9844ed.js new file mode 100644 index 0000000000..5170c025f2 --- /dev/null +++ b/assets/js/5ea22235.3f9844ed.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[1481,4074,3482,7310],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>u});var a=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),m=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=m(e.components);return a.createElement(c.Provider,{value:t},e.children)},l={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=m(n),u=i,g=p["".concat(c,".").concat(u)]||p[u]||l[u]||r;return n?a.createElement(g,o(o({ref:t},d),{},{components:n})):a.createElement(g,o({ref:t},d))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=p;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var m=2;m{n.d(t,{Z:()=>c});var a=n(67294),i=n(52263);const r="authorByline_VoxI",o="authorLabel_a70t",s="authorProfileImage_URwT";const c=function(e){let{frontMatter:t}=e;const{siteConfig:n}=(0,i.Z)(),c=n.customFields.authors;return a.createElement(a.Fragment,null,t.authors&&a.createElement("div",{className:"docAuthors"},a.createElement("hr",null),t.authors.map((e=>a.createElement("div",{key:e,className:r},a.createElement("img",{className:s,src:`/img/${c[e].image?c[e].image:"default_author_profile_pic.png"}`,alt:`Profile picture for ${c[e].name}`}),a.createElement("div",null,a.createElement("div",{className:o},"Author:"),a.createElement("div",null,a.createElement("a",{href:c[e].link,target:"_blank"},c[e].name),", ",c[e].title))))),a.createElement("hr",null)))}},36773:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>s,toc:()=>m});var a=n(87462),i=(n(67294),n(3905));const r={},o=void 0,s={unversionedId:"howtos/solutions/microservices/common-data/microservices-arch",id:"howtos/solutions/microservices/common-data/microservices-arch",title:"microservices-arch",description:"Lets take a look at the architecture of the demo application:",source:"@site/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",sourceDirName:"howtos/solutions/microservices/common-data",slug:"/howtos/solutions/microservices/common-data/microservices-arch",permalink:"/howtos/solutions/microservices/common-data/microservices-arch",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",tags:[],version:"current",lastUpdatedAt:1702551239,formattedLastUpdatedAt:"Dec 14, 2023",frontMatter:{}},c={},m=[],d={toc:m};function l(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Lets take a look at the architecture of the demo application:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"products service"),": handles querying products from the database and returning them to the frontend"),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"orders service"),": handles validating and creating orders"),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"order history service"),": handles querying a customer's order history"),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"payments service"),": handles processing orders for payment"),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"api gateway"),": unifies the services under a single endpoint"),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"mongodb/ postgresql"),": serves as the write-optimized database for storing orders, order history, products, etc.")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"You don't need to use MongoDB/ Postgresql as your write-optimized database in the demo application; you can use other ",(0,i.kt)("u",null,(0,i.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"prisma supported databases"))," as well. This is just an example.")))}l.isMDXComponent=!0},80990:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>s,toc:()=>m});var a=n(87462),i=(n(67294),n(3905));const r={},o=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",id:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",title:"microservices-ecommerce-ai",description:"The e-commerce microservices application consists of a frontend, built using Next.js with TailwindCSS. The application backend uses Node.js. The data is stored in Redis and either MongoDB or PostgreSQL, using Prisma. Below are screenshots showcasing the frontend of the e-commerce app.",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705608576,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},m=[],d={toc:m};function l(e){let{components:t,...r}=e;return(0,i.kt)("wrapper",(0,a.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The e-commerce microservices application consists of a frontend, built using ",(0,i.kt)("a",{parentName:"p",href:"https://nextjs.org/"},"Next.js")," with ",(0,i.kt)("a",{parentName:"p",href:"https://tailwindcss.com/"},"TailwindCSS"),". The application backend uses ",(0,i.kt)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js"),". The data is stored in ",(0,i.kt)("a",{parentName:"p",href:"https://redis.com/try-free/"},"Redis")," and either MongoDB or PostgreSQL, using ",(0,i.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"Prisma"),". Below are screenshots showcasing the frontend of the e-commerce app."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dashboard:")," Displays a list of products with different search functionalities, configurable in the settings page.\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Products Page",src:n(7050).Z,width:"2618",height:"1194"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Settings:")," Accessible by clicking the gear icon at the top right of the dashboard. Control the search bar, chatbot visibility, and other features here.\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Settings Page",src:n(8461).Z,width:"1822",height:"956"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dashboard (Semantic Text Search):"),' Configured for semantic text search, the search bar enables natural language queries. Example: "pure cotton blue shirts."\n',(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Text Search",src:n(81168).Z,width:"1920",height:"900"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Dashboard (Semantic Image-Based Queries):"),' Configured for semantic image summary search, the search bar allows for image-based queries. Example: "Left chest nike logo."\n',(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Image Search",src:n(2680).Z,width:"2608",height:"1216"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Chat Bot:")," Located at the bottom right corner of the page, assisting in product searches and detailed views.\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Chat Bot",src:n(99609).Z,width:"1920",height:"911"})),(0,i.kt)("p",null,"Selecting a product in the chat displays its details on the dashboard.\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Product Details",src:n(73064).Z,width:"2624",height:"1252"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Shopping Cart:"),' Add products to the cart and check out using the "Buy Now" button.\n',(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Shopping Cart",src:n(12224).Z,width:"2624",height:"1244"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Order History:")," Post-purchase, the 'Orders' link in the top navigation bar shows the order status and history.\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Order History Page",src:n(14065).Z,width:"2609",height:"674"})),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Admin Panel:")," Accessible via the 'admin' link in the top navigation. Displays purchase statistics and trending products.\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:n(37740).Z,width:"2604",height:"1230"}),"\n",(0,i.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:n(96127).Z,width:"2608",height:"858"})))}l.isMDXComponent=!0},10992:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>r,metadata:()=>s,toc:()=>m});var a=n(87462),i=(n(67294),n(3905));const r={},o=void 0,s={unversionedId:"howtos/solutions/vector/common-ai/microservices-source-code-ai",id:"howtos/solutions/vector/common-ai/microservices-source-code-ai",title:"microservices-source-code-ai",description:"Below is a command to the clone the source code for the application used in this tutorial",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705611366,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},m=[],d={toc:m};function l(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("admonition",{title:"GITHUB CODE",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Below is a command to the clone the source code for the application used in this tutorial"),(0,i.kt)("p",{parentName:"admonition"},"git clone --branch v9.2.0 ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"},"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"))))}l.isMDXComponent=!0},48815:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>f,frontMatter:()=>d,metadata:()=>p,toc:()=>g});var a=n(87462),i=(n(67294),n(3905)),r=n(50358),o=n(36773),s=n(80990);const c=n.p+"assets/images/product-img-741e131fef5eb5774118950873e3a5da.webp";var m=n(10992);const d={id:"index-image-summary-search",title:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",sidebar_label:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",slug:"/howtos/solutions/vector/image-summary-search",authors:["prasan","will"]},l=void 0,p={unversionedId:"howtos/solutions/vector/image-summary-search/index-image-summary-search",id:"howtos/solutions/vector/image-summary-search/index-image-summary-search",title:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",description:"What you will learn in this tutorial",source:"@site/docs/howtos/solutions/vector/image-summary-search/index-image-summary-search.mdx",sourceDirName:"howtos/solutions/vector/image-summary-search",slug:"/howtos/solutions/vector/image-summary-search",permalink:"/howtos/solutions/vector/image-summary-search",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/image-summary-search/index-image-summary-search.mdx",tags:[],version:"current",lastUpdatedAt:1705611366,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{id:"index-image-summary-search",title:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",sidebar_label:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",slug:"/howtos/solutions/vector/image-summary-search",authors:["prasan","will"]},sidebar:"docs",previous:{title:"Semantic Text Search Using LangChain (OpenAI) and Redis",permalink:"/howtos/solutions/vector/semantic-text-search"},next:{title:"How to build a Real-Time Leaderboard app Using Redis",permalink:"/howtos/leaderboard"}},u={},g=[{value:"What you will learn in this tutorial",id:"what-you-will-learn-in-this-tutorial",level:2},{value:"Terminology",id:"terminology",level:2},{value:"Microservices architecture for an e-commerce application",id:"microservices-architecture-for-an-e-commerce-application",level:2},{value:"E-commerce application frontend using Next.js and Tailwind",id:"e-commerce-application-frontend-using-nextjs-and-tailwind",level:2},{value:"Database setup",id:"database-setup",level:2},{value:"Sample data",id:"sample-data",level:3},{value:"Generating OpenAI image summary",id:"generating-openai-image-summary",level:3},{value:"Sample image & OpenAI summary",id:"sample-image--openai-summary",level:3},{value:"Seeding Image summary embeddings",id:"seeding-image-summary-embeddings",level:3},{value:"Setting up the search API",id:"setting-up-the-search-api",level:2},{value:"API end point",id:"api-end-point",level:3},{value:"API implementation",id:"api-implementation",level:3},{value:"Frontend UI",id:"frontend-ui",level:3},{value:"Ready to use Redis for semantic image based queries?",id:"ready-to-use-redis-for-semantic-image-based-queries",level:2},{value:"Further reading",id:"further-reading",level:2}],h={toc:g};function f(e){let{components:t,...l}=e;return(0,i.kt)("wrapper",(0,a.Z)({},h,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)(r.Z,{frontMatter:d,mdxType:"Authors"}),(0,i.kt)("h2",{id:"what-you-will-learn-in-this-tutorial"},"What you will learn in this tutorial"),(0,i.kt)("p",null,"This tutorial demonstrates how to perform semantic search on product images using LangChain (OpenAI) and Redis. Specifically, we'll cover the following topics:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"E-Commerce Application Context")," : Consider a sample e-commerce application scenario where customers can utilize image-based queries for product searches, add items to their shopping cart, and complete purchases, thereby highlighting a real-world application of semantic search.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Database setup")," : This involves generating descriptive summaries for product images, creating semantic embeddings for generated summaries and efficiently storing them in Redis.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Setting up the search API")," : This API is designed to process user queries in the context of image content. It integrates the capabilities of OpenAI for semantic analysis with Redis for efficient data retrieval and storage."))),(0,i.kt)("h2",{id:"terminology"},"Terminology"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("a",{parentName:"strong",href:"https://js.langchain.com"},"LangChain"))," is an innovative library for building language model applications. It offers a structured way to combine different components like language models (e.g., OpenAI's models), storage solutions (like Redis), and custom logic. This modular approach facilitates the creation of sophisticated AI applications."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("a",{parentName:"strong",href:"https://openai.com/"},"OpenAI"))," provides advanced language models like GPT-3, which have revolutionized the field with their ability to understand and generate human-like text. These models form the backbone of many modern AI applications including semantic text/ image search and chatbots."),(0,i.kt)("h2",{id:"microservices-architecture-for-an-e-commerce-application"},"Microservices architecture for an e-commerce application"),(0,i.kt)(m.default,{mdxType:"SourceCode"}),(0,i.kt)(o.default,{mdxType:"InitialMicroservicesArchitecture"}),(0,i.kt)("h2",{id:"e-commerce-application-frontend-using-nextjs-and-tailwind"},"E-commerce application frontend using Next.js and Tailwind"),(0,i.kt)(s.default,{mdxType:"MicroservicesEcommerceAIDesign"}),(0,i.kt)("h2",{id:"database-setup"},"Database setup"),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Sign up for an ",(0,i.kt)("u",null,(0,i.kt)("a",{parentName:"p",href:"https://platform.openai.com/"},"OpenAI account"))," to get your API key to be used in the demo (add OPEN_AI_API_KEY variable in .env file). You can also refer to the ",(0,i.kt)("u",null,(0,i.kt)("a",{parentName:"p",href:"https://platform.openai.com/docs/api-reference/introduction"},"OpenAI API documentation"))," for more information.")),(0,i.kt)(m.default,{mdxType:"SourceCode"}),(0,i.kt)("h3",{id:"sample-data"},"Sample data"),(0,i.kt)("p",null,"In this tutorial, we'll use a simplified e-commerce dataset. Specifically, our JSON structure includes ",(0,i.kt)("inlineCode",{parentName:"p"},"product")," details and a key named ",(0,i.kt)("inlineCode",{parentName:"p"},"styleImages_default_imageURL"),", which links to an image of the product. This image will be the focus of our AI-driven semantic search."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/fashion-dataset/001/products/*.json"',title:'"database/fashion-dataset/001/products/*.json"'},"const products = [\n {\n productId: '11000',\n price: 3995,\n productDisplayName: 'Puma Men Slick 3HD Yellow Black Watches',\n variantName: 'Slick 3HD Yellow',\n brandName: 'Puma',\n // Additional product details...\n styleImages_default_imageURL:\n 'http://host.docker.internal:8080/images/11000.jpg',\n // Other properties...\n },\n // Additional products...\n];\n")),(0,i.kt)("h3",{id:"generating-openai-image-summary"},"Generating OpenAI image summary"),(0,i.kt)("p",null,"The following code segment outlines the process of generating a text summary for a product image using OpenAI's capabilities. We'll first convert the image URL to a base64 string using ",(0,i.kt)("inlineCode",{parentName:"p"},"fetchImageAndConvertToBase64")," function and then utilize OpenAI to generate a summary of the image using ",(0,i.kt)("inlineCode",{parentName:"p"},"getOpenAIImageSummary")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/src/open-ai-image.ts"',title:'"database/src/open-ai-image.ts"'},"import {\n ChatOpenAI,\n ChatOpenAICallOptions,\n} from 'langchain/chat_models/openai';\nimport { HumanMessage } from 'langchain/schema';\nimport { Document } from 'langchain/document';\nimport { OpenAIEmbeddings } from 'langchain/embeddings/openai';\nimport { RedisVectorStore } from 'langchain/vectorstores/redis';\n\nlet llm: ChatOpenAI;\n\n// Instantiates the LangChain ChatOpenAI instance\nconst getOpenAIVisionInstance = (_openAIApiKey: string) => {\n //OpenAI supports images with text in input messages with their gpt-4-vision-preview.\n if (!llm) {\n llm = new ChatOpenAI({\n openAIApiKey: _openAIApiKey,\n modelName: 'gpt-4-vision-preview',\n maxTokens: 1024,\n });\n }\n return llm;\n};\n\nconst fetchImageAndConvertToBase64 = async (_imageURL: string) => {\n let base64Image = '';\n try {\n const response = await axios.get(_imageURL, {\n responseType: 'arraybuffer',\n });\n // Convert image to Base64\n base64Image = Buffer.from(response.data, 'binary').toString('base64');\n } catch (error) {\n console.error(\n `Error fetching or converting the image: ${_imageURL}`,\n error,\n );\n }\n return base64Image;\n};\n\n// Generates an OpenAI summary for a given base64 image string\nconst getOpenAIImageSummary = async (\n _openAIApiKey: string,\n _base64Image: string,\n _product: Prisma.ProductCreateInput,\n) => {\n /*\n Reference : https://js.langchain.com/docs/integrations/chat/openai#multimodal-messages\n\n - This function utilizes OpenAI's multimodal capabilities to generate a summary from the image. \n - It constructs a prompt that combines the product description with the image.\n - OpenAI's vision model then processes this prompt to generate a detailed summary.\n\n */\n let imageSummary = '';\n\n try {\n if (_openAIApiKey && _base64Image && _product) {\n const llmInst = getOpenAIVisionInstance(_openAIApiKey);\n\n const text = `Below are the product details and image of an e-commerce product for reference. Please conduct and provide a comprehensive analysis of the product depicted in the image . \n \n Product Details:\n ${_product.productDescriptors_description_value}\n \n Image:\n `;\n // Constructing a multimodal message combining text and image\n const imagePromptMessage = new HumanMessage({\n content: [\n {\n type: 'text',\n text: text,\n },\n {\n type: 'image_url',\n image_url: {\n url: `data:image/jpeg;base64,${_base64Image}`,\n detail: 'high', // low, high (if you want more detail)\n },\n },\n ],\n });\n\n // Invoking the LangChain ChatOpenAI model with the constructed message\n const response = await llmInst.invoke([imagePromptMessage]);\n if (response?.content) {\n imageSummary = response.content;\n }\n }\n } catch (err) {\n console.log(\n `Error generating OpenAIImageSummary for product id ${_product.productId}`,\n err,\n );\n }\n return imageSummary;\n};\n")),(0,i.kt)("h3",{id:"sample-image--openai-summary"},"Sample image & OpenAI summary"),(0,i.kt)("p",null,"The following section demonstrates the result of the above process. We'll use the image of a Puma T-shirt and generate a summary using OpenAI's capabilities."),(0,i.kt)("img",{src:c,alt:"Sample Product Image",width:"500",className:"margin-bottom--md"}),(0,i.kt)("p",null,"Comprehensive summary generated by the OpenAI model is as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-txt"},"This product is a black round neck T-shirt featuring a design consistent with the Puma brand aesthetic, which includes their iconic leaping cat logo in a contrasting yellow color placed prominently across the chest area. The T-shirt is made from 100% cotton, suggesting it is likely to be breathable and soft to the touch. It has a classic short-sleeve design with a ribbed neckline for added texture and durability. There is also mention of a vented hem, which may offer additional comfort and mobility.\n\nThe T-shirt is described to have a 'comfort' fit, which typically means it is designed to be neither too tight nor too loose, allowing for ease of movement without being baggy. This could be ideal for casual wear or active use.\n\nCare instructions are also comprehensive, advising a gentle machine wash with similar colors in cool water at 30 degrees Celsius, indicating it is relatively easy to care for. However, one should avoid bleaching, tumble drying, and dry cleaning it, but a warm iron is permissible.\n\nLooking at the image provided:\n\n- The T-shirt appears to fit the model well, in accordance with the described 'comfort' fit.\n- The color contrast between the T-shirt and the graphic gives the garment a modern, sporty look.\n- The model is paired with denim jeans, showcasing the T-shirt's versatility for casual occasions. However, the product description suggests it can be part of an athletic ensemble when combined with Puma shorts and shoes.\n- Considering the model's statistics, prospective buyers could infer how this T-shirt might fit on a person with similar measurements.\n\nOverall, the T-shirt is positioned as a versatile item suitable for both lifestyle and sporting activities, with a strong brand identity through the graphic, and is likely comfortable and easy to maintain based on the product details provided.\n")),(0,i.kt)("h3",{id:"seeding-image-summary-embeddings"},"Seeding Image summary embeddings"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"addImageSummaryEmbeddingsToRedis")," function plays a critical role in integrating AI-generated image summaries with Redis. This process involves two main steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Generating Vector Documents"),": Utilizing the ",(0,i.kt)("inlineCode",{parentName:"p"},"getImageSummaryVectorDocuments")," function, we transform image summaries into vector documents. This transformation is crucial as it converts textual summaries into a format suitable for Redis storage.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Seeding Embeddings into Redis"),": The ",(0,i.kt)("inlineCode",{parentName:"p"},"seedImageSummaryEmbeddings")," function is then employed to store these vector documents into Redis. This step is essential for enabling efficient retrieval and search capabilities within the Redis database."))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"// Function to generate vector documents from image summaries\nconst getImageSummaryVectorDocuments = async (\n _products: Prisma.ProductCreateInput[],\n _openAIApiKey: string,\n) => {\n const vectorDocs: Document[] = [];\n\n if (_products?.length > 0) {\n let count = 1;\n for (let product of _products) {\n if (product) {\n let imageURL = product.styleImages_default_imageURL; //cdn url\n const imageData = await fetchImageAndConvertToBase64(imageURL);\n imageSummary = await getOpenAIImageSummary(\n _openAIApiKey,\n imageData,\n product,\n );\n console.log(\n `openAI imageSummary #${count++} generated for product id: ${\n product.productId\n }`,\n );\n\n if (imageSummary) {\n let doc = new Document({\n metadata: {\n productId: product.productId,\n imageURL: imageURL,\n },\n pageContent: imageSummary,\n });\n vectorDocs.push(doc);\n }\n }\n }\n }\n return vectorDocs;\n};\n\n// Seeding vector documents into Redis\nconst seedImageSummaryEmbeddings = async (\n vectorDocs: Document[],\n _redisClient: NodeRedisClientType,\n _openAIApiKey: string,\n) => {\n if (vectorDocs?.length && _redisClient && _openAIApiKey) {\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: _openAIApiKey,\n });\n const vectorStore = await RedisVectorStore.fromDocuments(\n vectorDocs,\n embeddings,\n {\n redisClient: _redisClient,\n indexName: 'openAIProductImgIdx',\n keyPrefix: 'openAIProductImgText:',\n },\n );\n console.log('seeding imageSummaryEmbeddings completed');\n }\n};\n\nconst addImageSummaryEmbeddingsToRedis = async (\n _products: Prisma.ProductCreateInput[],\n _redisClient: NodeRedisClientType,\n _openAIApiKey: string,\n) => {\n const vectorDocs = await getImageSummaryVectorDocuments(\n _products,\n _openAIApiKey,\n );\n\n await seedImageSummaryEmbeddings(vectorDocs, _redisClient, _openAIApiKey);\n};\n")),(0,i.kt)("p",null,"The image below shows the JSON structure of ",(0,i.kt)("strong",{parentName:"p"},"openAI image summary")," within RedisInsight.\n",(0,i.kt)("img",{alt:"Redis Insight AI products",src:n(57802).Z,width:"2322",height:"1426"})),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Download ",(0,i.kt)("u",null,(0,i.kt)("a",{parentName:"p",href:"https://redis.com/redis-enterprise/redis-insight/"},"RedisInsight"))," to visually explore your Redis data or to engage with raw Redis commands in the workbench.")),(0,i.kt)("h2",{id:"setting-up-the-search-api"},"Setting up the search API"),(0,i.kt)("h3",{id:"api-end-point"},"API end point"),(0,i.kt)("p",null,"This section covers the API request and response structure for ",(0,i.kt)("inlineCode",{parentName:"p"},"getProductsByVSSImageSummary"),", which is essential for retrieving products based on semantic search using image summaries."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Request Format")),(0,i.kt)("p",null,"The example request format for the API is as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'POST http://localhost:3000/products/getProductsByVSSImageSummary\n{\n "searchText":"Left chest nike logo",\n\n //optional\n "maxProductCount": 4, // 2 (default)\n "similarityScoreLimit":0.2, // 0.2 (default)\n}\n')),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Response Structure")),(0,i.kt)("p",null,"The response from the API is a JSON object containing an array of product details that match the semantic search criteria:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "data": [\n {\n "productId": "10017",\n "price": 3995,\n "productDisplayName": "Nike Women As The Windru Blue Jackets",\n "brandName": "Nike",\n "styleImages_default_imageURL": "http://host.docker.internal:8080/products/01/10017/product-img.webp",\n "productDescriptors_description_value": " Blue and White jacket made of 100% polyester, with an interior pocket ...",\n "stockQty": 25,\n "similarityScore": 0.163541972637,\n "imageSummary": "The product in the image is a blue and white jacket featuring a design consistent with the provided description. ..."\n }\n // Additional products...\n ],\n "error": null,\n "auth": "SES_fd57d7f4-3deb-418f-9a95-6749cd06e348"\n}\n')),(0,i.kt)("h3",{id:"api-implementation"},"API implementation"),(0,i.kt)("p",null,"The backend implementation of this API involves following steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"getProductsByVSSImageSummary")," function handles the API Request."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"getSimilarProductsScoreByVSSImageSummary")," function performs semantic search on image summaries. It integrates with ",(0,i.kt)("inlineCode",{parentName:"li"},"OpenAI's")," semantic analysis capabilities to interpret the searchText and identify relevant products from ",(0,i.kt)("inlineCode",{parentName:"li"},"Redis")," vector store.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"const getSimilarProductsScoreByVSSImageSummary = async (\n _params: IParamsGetProductsByVSS,\n) => {\n let {\n standAloneQuestion,\n openAIApiKey,\n\n //optional\n KNN,\n scoreLimit,\n } = _params;\n\n let vectorDocs: Document[] = [];\n const client = getNodeRedisClient();\n\n KNN = KNN || 2;\n scoreLimit = scoreLimit || 1;\n\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: openAIApiKey,\n });\n\n // create vector store\n const vectorStore = new RedisVectorStore(embeddings, {\n redisClient: client,\n indexName: 'openAIProductImgIdx',\n keyPrefix: 'openAIProductImgText:',\n });\n\n // search for similar products\n const vectorDocsWithScore = await vectorStore.similaritySearchWithScore(\n standAloneQuestion,\n KNN,\n );\n\n // filter by scoreLimit\n for (let [doc, score] of vectorDocsWithScore) {\n if (score <= scoreLimit) {\n doc['similarityScore'] = score;\n vectorDocs.push(doc);\n }\n }\n\n return vectorDocs;\n};\n")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/service-impl.ts"',title:'"server/src/services/products/src/service-impl.ts"'},"const getProductsByVSSImageSummary = async (\n productsVSSFilter: IProductsVSSBodyFilter,\n) => {\n let { searchText, maxProductCount, similarityScoreLimit } = productsVSSFilter;\n let products: IProduct[] = [];\n\n const openAIApiKey = process.env.OPEN_AI_API_KEY || '';\n maxProductCount = maxProductCount || 2;\n similarityScoreLimit = similarityScoreLimit || 0.2;\n\n //VSS search\n const vectorDocs = await getSimilarProductsScoreByVSSImageSummary({\n standAloneQuestion: searchText,\n openAIApiKey: openAIApiKey,\n KNN: maxProductCount,\n scoreLimit: similarityScoreLimit,\n });\n\n if (vectorDocs?.length) {\n const productIds = vectorDocs.map((doc) => doc?.metadata?.productId);\n\n //get product with details\n products = await getProductByIds(productIds, true);\n }\n\n //...\n\n return products;\n};\n")),(0,i.kt)("h3",{id:"frontend-ui"},"Frontend UI"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Settings configuration"),": Initially, ensure that the ",(0,i.kt)("inlineCode",{parentName:"p"},"Semantic image summary search")," option is enabled in the settings page.\n",(0,i.kt)("img",{alt:"settings page",src:n(4871).Z,width:"1758",height:"956"}))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Performing a search"),": On the dashboard page, users can conduct searches using image-based queries. For example, if the query is ",(0,i.kt)("inlineCode",{parentName:"p"},"Left chest nike logo"),", the search results will display products like a Nike jacket, characterized by a logo on its left chest, reflecting the query."),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("img",{alt:"search page",src:n(23465).Z,width:"2608",height:"1216"}))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Viewing image summaries"),": Users can click on any product image to view the corresponding image summary generated by OpenAI. This feature offers an insightful glimpse into how AI interprets and summarizes visual content.\n",(0,i.kt)("img",{alt:"toggle image summary",src:n(90105).Z,width:"1274",height:"998"})))),(0,i.kt)("h2",{id:"ready-to-use-redis-for-semantic-image-based-queries"},"Ready to use Redis for semantic image based queries?"),(0,i.kt)("p",null,"Performing semantic search on image summaries is a powerful tool for e-commerce applications. It allows users to search for products based on their descriptions or images, enabling a more intuitive and efficient shopping experience. This tutorial has demonstrated how to integrate OpenAI's semantic analysis capabilities with Redis to create a robust search engine for e-commerce applications."),(0,i.kt)("h2",{id:"further-reading"},"Further reading"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("a",{parentName:"p",href:"/howtos/solutions/vector/getting-started-vector"},"Perform vector similarity search using Redis"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/get_started/quickstart"},"LangChain JS")),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://scrimba.com/learn/langchain"},"Learn LangChain")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/integrations/vectorstores/redis"},"LangChain redis integration")))))}f.isMDXComponent=!0},2680:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png"},81168:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png"},7050:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png"},99609:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png"},73064:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/03-ai-bot-product-ed8e13e4a32f72b952d683473a4c4d0f.png"},12224:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/04-ai-product-shopping-cart-5445685389780e76ba7135e47f0ad20b.png"},14065:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/05-order-history-fa1ebafcf8ac4ee027f5616a00044ee9.png"},37740:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/06-admin-charts-5ae00e6182be0b4ada06049f5d18d0aa.png"},96127:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/07-admin-top-trending-941390270b22d7b4243b386af50ec743.png"},8461:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png"},4871:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-ui-settings-8d7e67983fe497e10e32ae9d596f3433.png"},23465:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/02-ui-image-search-770befcd5c2129a025fc5fe9058d286f.png"},90105:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/03-ui-toggle-image-summary-2f6a1e8369101b7ee64861cb94599a1c.jpg"},57802:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-ai-image-6cc94b6b258688ef091048bd8933f99e.png"}}]); \ No newline at end of file diff --git a/assets/js/5ef34981.82f51f0f.js b/assets/js/5ef34981.82f51f0f.js deleted file mode 100644 index 03aefdc9f2..0000000000 --- a/assets/js/5ef34981.82f51f0f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[8851],{3905:(e,a,t)=>{t.d(a,{Zo:()=>p,kt:()=>m});var r=t(67294);function o(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function n(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);a&&(r=r.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var a=1;a=0||(o[t]=e[t]);return o}(e,a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),d=function(e){var a=r.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},p=function(e){var a=d(e.components);return r.createElement(s.Provider,{value:a},e.children)},c={inlineCode:"code",wrapper:function(e){var a=e.children;return r.createElement(r.Fragment,{},a)}},u=r.forwardRef((function(e,a){var t=e.components,o=e.mdxType,n=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=d(t),m=o,h=u["".concat(s,".").concat(m)]||u[m]||c[m]||n;return t?r.createElement(h,i(i({ref:a},p),{},{components:t})):r.createElement(h,i({ref:a},p))}));function m(e,a){var t=arguments,o=a&&a.mdxType;if("string"==typeof e||o){var n=t.length,i=new Array(n);i[0]=u;var l={};for(var s in a)hasOwnProperty.call(a,s)&&(l[s]=a[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,i[1]=l;for(var d=2;d{t.d(a,{Z:()=>s});var r=t(67294),o=t(52263);const n="authorByline_VoxI",i="authorLabel_a70t",l="authorProfileImage_URwT";const s=function(e){let{frontMatter:a}=e;const{siteConfig:t}=(0,o.Z)(),s=t.customFields.authors;return r.createElement(r.Fragment,null,a.authors&&r.createElement("div",{className:"docAuthors"},r.createElement("hr",null),a.authors.map((e=>r.createElement("div",{key:e,className:n},r.createElement("img",{className:l,src:`/img/${s[e].image?s[e].image:"default_author_profile_pic.png"}`,alt:`Profile picture for ${s[e].name}`}),r.createElement("div",null,r.createElement("div",{className:i},"Author:"),r.createElement("div",null,r.createElement("a",{href:s[e].link,target:"_blank"},s[e].name),", ",s[e].title))))),r.createElement("hr",null)))}},92079:(e,a,t)=>{t.r(a),t.d(a,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var r=t(87462),o=(t(67294),t(3905)),n=t(50358);const i={id:"index-leaderboard",title:"How to build a Real-Time Leaderboard app Using Redis",sidebar_label:"How to build a Real-Time Leaderboard app Using Redis",slug:"/howtos/leaderboard",authors:["ajeet"]},l=void 0,s={unversionedId:"howtos/leaderboard/index-leaderboard",id:"howtos/leaderboard/index-leaderboard",title:"How to build a Real-Time Leaderboard app Using Redis",description:"The concept of a leaderboard\u2014a scoreboard showing the ranked names and current scores (or other data points) of the leading competitors\u2014is essential to the world of computer gaming, but leaderboards are now about more than just games. They are about gamification, a broader implementation that can include any group of people with a common goal (coworkers, students, sales groups, fitness groups, volunteers, and so on).",source:"@site/docs/howtos/leaderboard/index-leaderboard.mdx",sourceDirName:"howtos/leaderboard",slug:"/howtos/leaderboard",permalink:"/howtos/leaderboard",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/leaderboard/index-leaderboard.mdx",tags:[],version:"current",lastUpdatedAt:1700152680,formattedLastUpdatedAt:"Nov 16, 2023",frontMatter:{id:"index-leaderboard",title:"How to build a Real-Time Leaderboard app Using Redis",sidebar_label:"How to build a Real-Time Leaderboard app Using Redis",slug:"/howtos/leaderboard",authors:["ajeet"]},sidebar:"docs",previous:{title:"How to Build a GenAI Chatbot Using LangChain and Redis",permalink:"/howtos/solutions/vector/gen-ai-chatbot"},next:{title:"How to build a Rate Limiter using Redis",permalink:"/howtos/ratelimiting"}},d={},p=[{value:"Step 1. Install the below software",id:"step-1-install-the-below-software",level:3},{value:"Step 2. Clone the repository",id:"step-2-clone-the-repository",level:3},{value:"Step 3. Run docker compose",id:"step-3-run-docker-compose",level:3},{value:"Step 4. Verifying if containers are up and running",id:"step-4-verifying-if-containers-are-up-and-running",level:3},{value:"Step 5. Copy .env.example to create .env",id:"step-5-copy-envexample-to-create-env",level:3},{value:"Step 6. Run the backend",id:"step-6-run-the-backend",level:3},{value:"Step 7. Run the wrapper task",id:"step-7-run-the-wrapper-task",level:3},{value:"Step 8. Perform the build task",id:"step-8-perform-the-build-task",level:3},{value:"Step 9. Run your application",id:"step-9-run-your-application",level:3},{value:"Step 10. Access the leaderboard application",id:"step-10-access-the-leaderboard-application",level:3},{value:"How it works?",id:"how-it-works",level:3},{value:"How the data is stored:",id:"how-the-data-is-stored",level:4},{value:"How the data is accessed:",id:"how-the-data-is-accessed",level:4},{value:"References",id:"references",level:3}],c={toc:p};function u(e){let{components:a,...l}=e;return(0,o.kt)("wrapper",(0,r.Z)({},c,l,{components:a,mdxType:"MDXLayout"}),(0,o.kt)(n.Z,{frontMatter:i,mdxType:"Authors"}),(0,o.kt)("p",null,"The concept of a leaderboard\u2014a scoreboard showing the ranked names and current scores (or other data points) of the leading competitors\u2014is essential to the world of computer gaming, but leaderboards are now about more than just games. They are about gamification, a broader implementation that can include any group of people with a common goal (coworkers, students, sales groups, fitness groups, volunteers, and so on)."),(0,o.kt)("p",null,"Leaderboards can encourage healthy competition in a group by openly displaying the current ranking of each group member. They also provide a clear way to view the ongoing achievements of the entire team as members move towards a goal. Gamification of tasks and goals via leaderboards is a great way to motivate people by providing them with constant feedback of where they rank in comparison to other group members. Done well, this can lead to healthy competition that builds group cohesion."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"My Image",src:t(15620).Z,width:"2878",height:"1576"})),(0,o.kt)("h3",{id:"step-1-install-the-below-software"},"Step 1. Install the below software"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Docker (on mac: ",(0,o.kt)("a",{parentName:"li",href:"https://docs.docker.com/docker-for-mac/install/"},"https://docs.docker.com/docker-for-mac/install/"),")"),(0,o.kt)("li",{parentName:"ul"},"Docker Compose")),(0,o.kt)("h3",{id:"step-2-clone-the-repository"},"Step 2. Clone the repository"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"git clone https://github.com/redis-developer/basic-redis-leaderboard-demo-java\n")),(0,o.kt)("h3",{id:"step-3-run-docker-compose"},"Step 3. Run docker compose"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"docker network create global\ndocker-compose up -d --build\n")),(0,o.kt)("h3",{id:"step-4-verifying-if-containers-are-up-and-running"},"Step 4. Verifying if containers are up and running"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," docker-compose ps\n Name Command State Ports\n--------------------------------------------------------------------------------------------------\nredis.redisleaderboard.docker docker-entrypoint.sh redis ... Up 127.0.0.1:55000->6379/tcp\n")),(0,o.kt)("h3",{id:"step-5-copy-envexample-to-create-env"},"Step 5. Copy .env.example to create .env"),(0,o.kt)("p",null,"Provide the values for environment variables (if needed)"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"- REDIS_URL: Redis database endpoint URL\n- REDIS_HOST: Redis server host\n- REDIS_PORT: Redis server port\n- REDIS_DB: Redis server db index\n- REDIS_PASSWORD: Redis server password\n")),(0,o.kt)("p",null,"If you're using Redis Cloud, you must supply DB endpoint, password, port and the name of the database.\nIn case of local system, the entries look like as shown below:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"REDIS_URL=\nREDIS_HOST=redis://localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=\nREDIS_DB=\n")),(0,o.kt)("h3",{id:"step-6-run-the-backend"},"Step 6. Run the backend"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Install gradle")),(0,o.kt)("p",null,"Follow the following link ",(0,o.kt)("a",{parentName:"p",href:"https://gradle.org/install/"},"https://gradle.org/install/")," for your MacOS"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"brew install gradle\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Install JDK")),(0,o.kt)("p",null,"Follow the following link ",(0,o.kt)("a",{parentName:"p",href:"https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm"},"https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm")," for your MacOS"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"export $(cat .env | xargs)\n")),(0,o.kt)("h3",{id:"step-7-run-the-wrapper-task"},"Step 7. Run the wrapper task"),(0,o.kt)("p",null,"To use Wrapper, we need to generate some particular files. We'll generate these files using the built-in Gradle task called wrapper.\nNote that we need to generate these files only once."),(0,o.kt)("p",null,"Now, let's run the wrapper task in our project directory:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"gradle wrapper\n")),(0,o.kt)("p",null,"It should show the below results:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Welcome to Gradle 6.8.3!\n\nHere are the highlights of this release:\n - Faster Kotlin DSL script compilation\n - Vendor selection for Java toolchains\n - Convenient execution of tasks in composite builds\n - Consistent dependency resolution\n\nFor more details see https://docs.gradle.org/6.8.3/release-notes.html\n\nStarting a Gradle Daemon (subsequent builds will be faster)\n\nBUILD SUCCESSFUL in 29s\n1 actionable task: 1 executed\n")),(0,o.kt)("h3",{id:"step-8-perform-the-build-task"},"Step 8. Perform the build task"),(0,o.kt)("p",null,"The Gradle Wrapper is now available for building your project. It's time to run the wrapper script to perform the build task."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"./gradlew build\n% ./gradlew build\nDownloading https://services.gradle.org/distributions/gradle-6.8.3-bin.zip\n..........10%..........20%..........30%...........40%..........50%..........60%..........70%...........80%..........90%..........100%\nStarting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details\n\n> Task :test\n2021-03-01 07:08:42.962 INFO 3624 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'\n\nBUILD SUCCESSFUL in 1m 13s\n12 actionable tasks: 12 executed\n")),(0,o.kt)("h3",{id:"step-9-run-your-application"},"Step 9. Run your application"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"./gradlew run\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"> Task :run\n\n . ____ _ __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )\n ' |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot :: (v2.4.1)\n\n2021-03-01 07:09:59.610 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Starting BasicRedisLeaderLoardDemoJavaApplication using Java 13.0.2 on Ajeets-MacBook-Pro.local with PID 3672 (/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/build/classes/java/main started by ajeetraina in /Users/ajeetraina/projects/basic-redis-leaderboard-demo-java)\n2021-03-01 07:09:59.614 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : No active profile set, falling back to default profiles: default\n2021-03-01 07:09:59.661 INFO 3672 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable\n2021-03-01 07:09:59.661 INFO 3672 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'\n2021-03-01 07:10:00.481 INFO 3672 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 5000 (http)\n2021-03-01 07:10:00.492 INFO 3672 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]\n2021-03-01 07:10:00.492 INFO 3672 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]\n2021-03-01 07:10:00.551 INFO 3672 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext\n2021-03-01 07:10:00.551 INFO 3672 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 889 ms\n2021-03-01 07:10:00.756 INFO 3672 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'\n2021-03-01 07:10:00.845 INFO 3672 --- [ restartedMain] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: URL [file:/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/assets/index.html]\n2021-03-01 07:10:00.949 INFO 3672 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration :\n\nUsing generated security password: ea2d5326-b04c-4f93-b771-57bcb53f656e\n\n2021-03-01 07:10:01.016 INFO 3672 --- [ restartedMain] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@583fa06c, org.springframework.security.web.context.SecurityContextPersistenceFilter@524c0386, org.springframework.security.web.header.HeaderWriterFilter@c6e5d4e, org.springframework.security.web.authentication.logout.LogoutFilter@3e1f33e9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6790427f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@40ddf86, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1412ffa9, org.springframework.security.web.session.SessionManagementFilter@3eb6c20f, org.springframework.security.web.access.ExceptionTranslationFilter@21646e94, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@649e1b25]\n2021-03-01 07:10:01.043 INFO 3672 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729\n2021-03-01 07:10:01.065 INFO 3672 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5000 (http) with context path ''\n2021-03-01 07:10:01.093 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Started BasicRedisLeaderLoardDemoJavaApplication in 1.937 seconds (JVM running for 2.327)\n<=========----\x3e 75% EXECUTING [17s]\n> :run\n")),(0,o.kt)("h3",{id:"step-10-access-the-leaderboard-application"},"Step 10. Access the leaderboard application"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"My Image",src:t(15620).Z,width:"2878",height:"1576"})),(0,o.kt)("h3",{id:"how-it-works"},"How it works?"),(0,o.kt)("h4",{id:"how-the-data-is-stored"},"How the data is stored:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"The AAPL's details - market cap of 2.6 triillions and USA origin - are stored in a hash like below:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},' HSET "company:AAPL" symbol "AAPL" market_cap "2600000000000" country USA\n'))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"The Ranks of AAPL of 2.6 trillions are stored in a ZSET."),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZADD companyLeaderboard 2600000000000 company:AAPL\n")))),(0,o.kt)("h4",{id:"how-the-data-is-accessed"},"How the data is accessed:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Top 10 companies:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderboard 0 9 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"All companies:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderboard 0 -1 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Bottom 10 companies:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZRANGE companyLeaderboard 0 9 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Between rank 10 and 15:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderboard 9 14 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Show ranks of AAPL, FB and TSLA:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderBoard company:AAPL company:FB company:TSLA\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Adding 1 billion to market cap of FB company:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},' ZINCRBY companyLeaderBoard 1000000000 "company:FB"\n'))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Reducing 1 billion of market cap of FB company:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},' ZINCRBY companyLeaderBoard -1000000000 "company:FB"\n'))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Companies between 500 billion and 1 trillion:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZCOUNT companyLeaderBoard 500000000000 1000000000000\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Companies over a Trillion:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZCOUNT companyLeaderBoard 1000000000000 +inf\n")))),(0,o.kt)("h3",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-nodejs"},"How to build a Real-Time Leaderboard app using Redis & Nodejs")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-ruby"},"How to build a Real-Time Leaderboard app using Redis & Ruby")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-python"},"How to build a Real-Time Leaderboard app using Redis & Python")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-dotnet"},"How to build a Real-Time Leaderboard app using Redis & .NET")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-go"},"How to build a Real-Time Leaderboard app using Redis & Go"))))}u.isMDXComponent=!0},15620:(e,a,t)=>{t.d(a,{Z:()=>r});const r=t.p+"assets/images/leaderboard-4bb6a429bc363743888354f6b06631b8.png"}}]); \ No newline at end of file diff --git a/assets/js/5ef34981.8ee407d7.js b/assets/js/5ef34981.8ee407d7.js new file mode 100644 index 0000000000..73370c749f --- /dev/null +++ b/assets/js/5ef34981.8ee407d7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[8851],{3905:(e,a,t)=>{t.d(a,{Zo:()=>p,kt:()=>m});var r=t(67294);function o(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function n(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);a&&(r=r.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var a=1;a=0||(o[t]=e[t]);return o}(e,a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),d=function(e){var a=r.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},p=function(e){var a=d(e.components);return r.createElement(s.Provider,{value:a},e.children)},c={inlineCode:"code",wrapper:function(e){var a=e.children;return r.createElement(r.Fragment,{},a)}},u=r.forwardRef((function(e,a){var t=e.components,o=e.mdxType,n=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=d(t),m=o,h=u["".concat(s,".").concat(m)]||u[m]||c[m]||n;return t?r.createElement(h,i(i({ref:a},p),{},{components:t})):r.createElement(h,i({ref:a},p))}));function m(e,a){var t=arguments,o=a&&a.mdxType;if("string"==typeof e||o){var n=t.length,i=new Array(n);i[0]=u;var l={};for(var s in a)hasOwnProperty.call(a,s)&&(l[s]=a[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,i[1]=l;for(var d=2;d{t.d(a,{Z:()=>s});var r=t(67294),o=t(52263);const n="authorByline_VoxI",i="authorLabel_a70t",l="authorProfileImage_URwT";const s=function(e){let{frontMatter:a}=e;const{siteConfig:t}=(0,o.Z)(),s=t.customFields.authors;return r.createElement(r.Fragment,null,a.authors&&r.createElement("div",{className:"docAuthors"},r.createElement("hr",null),a.authors.map((e=>r.createElement("div",{key:e,className:n},r.createElement("img",{className:l,src:`/img/${s[e].image?s[e].image:"default_author_profile_pic.png"}`,alt:`Profile picture for ${s[e].name}`}),r.createElement("div",null,r.createElement("div",{className:i},"Author:"),r.createElement("div",null,r.createElement("a",{href:s[e].link,target:"_blank"},s[e].name),", ",s[e].title))))),r.createElement("hr",null)))}},92079:(e,a,t)=>{t.r(a),t.d(a,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var r=t(87462),o=(t(67294),t(3905)),n=t(50358);const i={id:"index-leaderboard",title:"How to build a Real-Time Leaderboard app Using Redis",sidebar_label:"How to build a Real-Time Leaderboard app Using Redis",slug:"/howtos/leaderboard",authors:["ajeet"]},l=void 0,s={unversionedId:"howtos/leaderboard/index-leaderboard",id:"howtos/leaderboard/index-leaderboard",title:"How to build a Real-Time Leaderboard app Using Redis",description:"The concept of a leaderboard\u2014a scoreboard showing the ranked names and current scores (or other data points) of the leading competitors\u2014is essential to the world of computer gaming, but leaderboards are now about more than just games. They are about gamification, a broader implementation that can include any group of people with a common goal (coworkers, students, sales groups, fitness groups, volunteers, and so on).",source:"@site/docs/howtos/leaderboard/index-leaderboard.mdx",sourceDirName:"howtos/leaderboard",slug:"/howtos/leaderboard",permalink:"/howtos/leaderboard",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/leaderboard/index-leaderboard.mdx",tags:[],version:"current",lastUpdatedAt:1700152680,formattedLastUpdatedAt:"Nov 16, 2023",frontMatter:{id:"index-leaderboard",title:"How to build a Real-Time Leaderboard app Using Redis",sidebar_label:"How to build a Real-Time Leaderboard app Using Redis",slug:"/howtos/leaderboard",authors:["ajeet"]},sidebar:"docs",previous:{title:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",permalink:"/howtos/solutions/vector/image-summary-search"},next:{title:"How to build a Rate Limiter using Redis",permalink:"/howtos/ratelimiting"}},d={},p=[{value:"Step 1. Install the below software",id:"step-1-install-the-below-software",level:3},{value:"Step 2. Clone the repository",id:"step-2-clone-the-repository",level:3},{value:"Step 3. Run docker compose",id:"step-3-run-docker-compose",level:3},{value:"Step 4. Verifying if containers are up and running",id:"step-4-verifying-if-containers-are-up-and-running",level:3},{value:"Step 5. Copy .env.example to create .env",id:"step-5-copy-envexample-to-create-env",level:3},{value:"Step 6. Run the backend",id:"step-6-run-the-backend",level:3},{value:"Step 7. Run the wrapper task",id:"step-7-run-the-wrapper-task",level:3},{value:"Step 8. Perform the build task",id:"step-8-perform-the-build-task",level:3},{value:"Step 9. Run your application",id:"step-9-run-your-application",level:3},{value:"Step 10. Access the leaderboard application",id:"step-10-access-the-leaderboard-application",level:3},{value:"How it works?",id:"how-it-works",level:3},{value:"How the data is stored:",id:"how-the-data-is-stored",level:4},{value:"How the data is accessed:",id:"how-the-data-is-accessed",level:4},{value:"References",id:"references",level:3}],c={toc:p};function u(e){let{components:a,...l}=e;return(0,o.kt)("wrapper",(0,r.Z)({},c,l,{components:a,mdxType:"MDXLayout"}),(0,o.kt)(n.Z,{frontMatter:i,mdxType:"Authors"}),(0,o.kt)("p",null,"The concept of a leaderboard\u2014a scoreboard showing the ranked names and current scores (or other data points) of the leading competitors\u2014is essential to the world of computer gaming, but leaderboards are now about more than just games. They are about gamification, a broader implementation that can include any group of people with a common goal (coworkers, students, sales groups, fitness groups, volunteers, and so on)."),(0,o.kt)("p",null,"Leaderboards can encourage healthy competition in a group by openly displaying the current ranking of each group member. They also provide a clear way to view the ongoing achievements of the entire team as members move towards a goal. Gamification of tasks and goals via leaderboards is a great way to motivate people by providing them with constant feedback of where they rank in comparison to other group members. Done well, this can lead to healthy competition that builds group cohesion."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"My Image",src:t(15620).Z,width:"2878",height:"1576"})),(0,o.kt)("h3",{id:"step-1-install-the-below-software"},"Step 1. Install the below software"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Docker (on mac: ",(0,o.kt)("a",{parentName:"li",href:"https://docs.docker.com/docker-for-mac/install/"},"https://docs.docker.com/docker-for-mac/install/"),")"),(0,o.kt)("li",{parentName:"ul"},"Docker Compose")),(0,o.kt)("h3",{id:"step-2-clone-the-repository"},"Step 2. Clone the repository"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"git clone https://github.com/redis-developer/basic-redis-leaderboard-demo-java\n")),(0,o.kt)("h3",{id:"step-3-run-docker-compose"},"Step 3. Run docker compose"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"docker network create global\ndocker-compose up -d --build\n")),(0,o.kt)("h3",{id:"step-4-verifying-if-containers-are-up-and-running"},"Step 4. Verifying if containers are up and running"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," docker-compose ps\n Name Command State Ports\n--------------------------------------------------------------------------------------------------\nredis.redisleaderboard.docker docker-entrypoint.sh redis ... Up 127.0.0.1:55000->6379/tcp\n")),(0,o.kt)("h3",{id:"step-5-copy-envexample-to-create-env"},"Step 5. Copy .env.example to create .env"),(0,o.kt)("p",null,"Provide the values for environment variables (if needed)"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"- REDIS_URL: Redis database endpoint URL\n- REDIS_HOST: Redis server host\n- REDIS_PORT: Redis server port\n- REDIS_DB: Redis server db index\n- REDIS_PASSWORD: Redis server password\n")),(0,o.kt)("p",null,"If you're using Redis Cloud, you must supply DB endpoint, password, port and the name of the database.\nIn case of local system, the entries look like as shown below:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"REDIS_URL=\nREDIS_HOST=redis://localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=\nREDIS_DB=\n")),(0,o.kt)("h3",{id:"step-6-run-the-backend"},"Step 6. Run the backend"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Install gradle")),(0,o.kt)("p",null,"Follow the following link ",(0,o.kt)("a",{parentName:"p",href:"https://gradle.org/install/"},"https://gradle.org/install/")," for your MacOS"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"brew install gradle\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Install JDK")),(0,o.kt)("p",null,"Follow the following link ",(0,o.kt)("a",{parentName:"p",href:"https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm"},"https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm")," for your MacOS"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"export $(cat .env | xargs)\n")),(0,o.kt)("h3",{id:"step-7-run-the-wrapper-task"},"Step 7. Run the wrapper task"),(0,o.kt)("p",null,"To use Wrapper, we need to generate some particular files. We'll generate these files using the built-in Gradle task called wrapper.\nNote that we need to generate these files only once."),(0,o.kt)("p",null,"Now, let's run the wrapper task in our project directory:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"gradle wrapper\n")),(0,o.kt)("p",null,"It should show the below results:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Welcome to Gradle 6.8.3!\n\nHere are the highlights of this release:\n - Faster Kotlin DSL script compilation\n - Vendor selection for Java toolchains\n - Convenient execution of tasks in composite builds\n - Consistent dependency resolution\n\nFor more details see https://docs.gradle.org/6.8.3/release-notes.html\n\nStarting a Gradle Daemon (subsequent builds will be faster)\n\nBUILD SUCCESSFUL in 29s\n1 actionable task: 1 executed\n")),(0,o.kt)("h3",{id:"step-8-perform-the-build-task"},"Step 8. Perform the build task"),(0,o.kt)("p",null,"The Gradle Wrapper is now available for building your project. It's time to run the wrapper script to perform the build task."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"./gradlew build\n% ./gradlew build\nDownloading https://services.gradle.org/distributions/gradle-6.8.3-bin.zip\n..........10%..........20%..........30%...........40%..........50%..........60%..........70%...........80%..........90%..........100%\nStarting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details\n\n> Task :test\n2021-03-01 07:08:42.962 INFO 3624 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'\n\nBUILD SUCCESSFUL in 1m 13s\n12 actionable tasks: 12 executed\n")),(0,o.kt)("h3",{id:"step-9-run-your-application"},"Step 9. Run your application"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"./gradlew run\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"> Task :run\n\n . ____ _ __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )\n ' |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot :: (v2.4.1)\n\n2021-03-01 07:09:59.610 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Starting BasicRedisLeaderLoardDemoJavaApplication using Java 13.0.2 on Ajeets-MacBook-Pro.local with PID 3672 (/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/build/classes/java/main started by ajeetraina in /Users/ajeetraina/projects/basic-redis-leaderboard-demo-java)\n2021-03-01 07:09:59.614 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : No active profile set, falling back to default profiles: default\n2021-03-01 07:09:59.661 INFO 3672 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable\n2021-03-01 07:09:59.661 INFO 3672 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'\n2021-03-01 07:10:00.481 INFO 3672 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 5000 (http)\n2021-03-01 07:10:00.492 INFO 3672 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]\n2021-03-01 07:10:00.492 INFO 3672 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]\n2021-03-01 07:10:00.551 INFO 3672 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext\n2021-03-01 07:10:00.551 INFO 3672 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 889 ms\n2021-03-01 07:10:00.756 INFO 3672 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'\n2021-03-01 07:10:00.845 INFO 3672 --- [ restartedMain] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: URL [file:/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/assets/index.html]\n2021-03-01 07:10:00.949 INFO 3672 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration :\n\nUsing generated security password: ea2d5326-b04c-4f93-b771-57bcb53f656e\n\n2021-03-01 07:10:01.016 INFO 3672 --- [ restartedMain] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@583fa06c, org.springframework.security.web.context.SecurityContextPersistenceFilter@524c0386, org.springframework.security.web.header.HeaderWriterFilter@c6e5d4e, org.springframework.security.web.authentication.logout.LogoutFilter@3e1f33e9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6790427f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@40ddf86, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1412ffa9, org.springframework.security.web.session.SessionManagementFilter@3eb6c20f, org.springframework.security.web.access.ExceptionTranslationFilter@21646e94, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@649e1b25]\n2021-03-01 07:10:01.043 INFO 3672 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729\n2021-03-01 07:10:01.065 INFO 3672 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5000 (http) with context path ''\n2021-03-01 07:10:01.093 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Started BasicRedisLeaderLoardDemoJavaApplication in 1.937 seconds (JVM running for 2.327)\n<=========----\x3e 75% EXECUTING [17s]\n> :run\n")),(0,o.kt)("h3",{id:"step-10-access-the-leaderboard-application"},"Step 10. Access the leaderboard application"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"My Image",src:t(15620).Z,width:"2878",height:"1576"})),(0,o.kt)("h3",{id:"how-it-works"},"How it works?"),(0,o.kt)("h4",{id:"how-the-data-is-stored"},"How the data is stored:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"The AAPL's details - market cap of 2.6 triillions and USA origin - are stored in a hash like below:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},' HSET "company:AAPL" symbol "AAPL" market_cap "2600000000000" country USA\n'))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"The Ranks of AAPL of 2.6 trillions are stored in a ZSET."),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZADD companyLeaderboard 2600000000000 company:AAPL\n")))),(0,o.kt)("h4",{id:"how-the-data-is-accessed"},"How the data is accessed:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Top 10 companies:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderboard 0 9 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"All companies:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderboard 0 -1 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Bottom 10 companies:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZRANGE companyLeaderboard 0 9 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Between rank 10 and 15:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderboard 9 14 WITHSCORES\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Show ranks of AAPL, FB and TSLA:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZREVRANGE companyLeaderBoard company:AAPL company:FB company:TSLA\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Adding 1 billion to market cap of FB company:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},' ZINCRBY companyLeaderBoard 1000000000 "company:FB"\n'))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Reducing 1 billion of market cap of FB company:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},' ZINCRBY companyLeaderBoard -1000000000 "company:FB"\n'))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Companies between 500 billion and 1 trillion:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZCOUNT companyLeaderBoard 500000000000 1000000000000\n"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Companies over a Trillion:"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," ZCOUNT companyLeaderBoard 1000000000000 +inf\n")))),(0,o.kt)("h3",{id:"references"},"References"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-nodejs"},"How to build a Real-Time Leaderboard app using Redis & Nodejs")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-ruby"},"How to build a Real-Time Leaderboard app using Redis & Ruby")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-python"},"How to build a Real-Time Leaderboard app using Redis & Python")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-dotnet"},"How to build a Real-Time Leaderboard app using Redis & .NET")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/redis-developer/basic-redis-leaderboard-demo-go"},"How to build a Real-Time Leaderboard app using Redis & Go"))))}u.isMDXComponent=!0},15620:(e,a,t)=>{t.d(a,{Z:()=>r});const r=t.p+"assets/images/leaderboard-4bb6a429bc363743888354f6b06631b8.png"}}]); \ No newline at end of file diff --git a/assets/js/6c272831.032c3dfd.js b/assets/js/6c272831.032c3dfd.js new file mode 100644 index 0000000000..e02990cc6a --- /dev/null +++ b/assets/js/6c272831.032c3dfd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[4936],{71131:(e,i,t)=>{t.d(i,{Z:()=>m});var s=t(67294),o=t(3905),a=t(52195);const n="riContainer_bco2",r="riDescriptionShort_E27B",c="riDetail_wzFs",d="riIcon_yDou",l="riTitle_x6vI",u="riDescription_RDnu",h="riMore_apRP";var p=t(86010);const m=e=>{const[i,t]=s.useState(!1);return s.createElement("a",{href:e.page,className:n},s.createElement("div",{className:r},s.createElement("div",{className:d},s.createElement("span",{className:"fe fe-zap"})),s.createElement("div",{className:c},s.createElement("div",{className:l},s.createElement("a",{href:e.page},e.title)),s.createElement("div",{className:u},e.description,s.Children.count(e.children)>0&&s.createElement("span",{className:(0,p.Z)(h,"fe","fe-more-horizontal"),onClick:()=>t(!i)})))),i&&s.createElement("div",{className:"ri-description-long"},s.createElement(o.Zo,{components:a.Z},e.children)))}},35077:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>n,metadata:()=>c,toc:()=>l});var s=t(87462),o=(t(67294),t(3905)),a=t(71131);const n={id:"index-solutions",title:"Solution Tutorials",sidebar_label:"Overview",slug:"/howtos/solutions"},r=void 0,c={unversionedId:"howtos/solutions/index-solutions",id:"howtos/solutions/index-solutions",title:"Solution Tutorials",description:"This page provides a listing of dozens of popular app solution tutorials from Redis.",source:"@site/docs/howtos/solutions/index-solutions.mdx",sourceDirName:"howtos/solutions",slug:"/howtos/solutions",permalink:"/howtos/solutions",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/index-solutions.mdx",tags:[],version:"current",lastUpdatedAt:1705411821,formattedLastUpdatedAt:"Jan 16, 2024",frontMatter:{id:"index-solutions",title:"Solution Tutorials",sidebar_label:"Overview",slug:"/howtos/solutions"},sidebar:"docs",previous:{title:"Cheat sheet",permalink:"/howtos/quick-start/cheat-sheet"},next:{title:"How to Build an E-Commerce App Using Redis with the CQRS Pattern",permalink:"/howtos/solutions/microservices/cqrs"}},d={},l=[{value:"Microservices",id:"microservices",level:2},{value:"Fraud detection",id:"fraud-detection",level:2},{value:"Caching architecture",id:"caching-architecture",level:2},{value:"Real-time Inventory",id:"real-time-inventory",level:2},{value:"Mobile Banking",id:"mobile-banking",level:2},{value:"Vectors",id:"vectors",level:2}],u={toc:l};function h(e){let{components:i,...t}=e;return(0,o.kt)("wrapper",(0,s.Z)({},u,t,{components:i,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"This page provides a listing of dozens of popular app solution tutorials from Redis."),(0,o.kt)("h2",{id:"microservices"},"Microservices"),(0,o.kt)("p",null,"Learn how to easily build, test and deploy code for common microservice and caching design patterns across different industries using Redis."),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"CQRS Pattern",description:"How to build an e-commerce app using Redis with the CQRS Pattern",page:"/howtos/solutions/microservices/cqrs",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Interservice Communication",description:"Microservices Communication with Redis streams",page:"/howtos/solutions/microservices/interservice-communication",mdxType:"RedisCard"}))),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Query Caching Pattern",description:"How to use Redis for Query Caching",page:"/howtos/solutions/microservices/caching",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"API Gateway Caching",description:"How to use Redis for API Gateway Caching",page:"/howtos/solutions/microservices/api-gateway-caching",mdxType:"RedisCard"}))),(0,o.kt)("h2",{id:"fraud-detection"},"Fraud detection"),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Digital Identity Validation",description:"How to Handle Digital Identity Validation Using Redis",page:"/howtos/solutions/fraud-detection/digital-identity-validation",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Transaction Risk Scoring",description:"How to use Redis for Transaction risk scoring",page:"/howtos/solutions/fraud-detection/transaction-risk-scoring",mdxType:"RedisCard"}))),(0,o.kt)("h2",{id:"caching-architecture"},"Caching architecture"),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Write Behind Caching",description:"How to use Redis for Write-behind Caching",page:"/howtos/solutions/caching-architecture/write-behind",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Write Through caching",description:"How to use Redis for Write through caching strategy",page:"/howtos/solutions/caching-architecture/write-through",mdxType:"RedisCard"}))),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Cache Prefetching",description:"How to use Redis for Cache Prefetching Strategy",page:"/howtos/solutions/caching-architecture/cache-prefetching",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Cache Aside (Query Caching)",description:"How to use Redis for Cache-aside",page:"/howtos/solutions/microservices/caching",mdxType:"RedisCard"}))),(0,o.kt)("h2",{id:"real-time-inventory"},"Real-time Inventory"),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Available to Promise",description:"Available to Promise in Real-time Inventory Using Redis",page:"/howtos/solutions/real-time-inventory/available-to-promise",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Real-time Local Inventory Search (GeoSpatial)",description:"Real-time Local Inventory Search Using Redis",page:"/howtos/solutions/real-time-inventory/local-inventory-search",mdxType:"RedisCard"}))),(0,o.kt)("h2",{id:"mobile-banking"},"Mobile Banking"),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Authentication and Session Storage",description:"Mobile Banking Authentication and Session Storage Using Redis",page:"/howtos/solutions/mobile-banking/session-management",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Account Dashboard",description:"Mobile Banking Account Dashboard Using Redis",page:"/howtos/solutions/mobile-banking/account-dashboard",mdxType:"RedisCard"}))),(0,o.kt)("h2",{id:"vectors"},"Vectors"),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Vector Similarity Search",description:"Getting Started with Vector Search Using Redis in NodeJS",page:"/howtos/solutions/vector/getting-started-vector",mdxType:"RedisCard"})),(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"GenAI Chatbot",description:"Build a GenAI Chatbot Using LangChain and Redis",page:"/howtos/solutions/vector/gen-ai-chatbot",mdxType:"RedisCard"}))),(0,o.kt)("div",{class:"row"},(0,o.kt)("div",{class:"col"},(0,o.kt)(a.Z,{title:"Semantic Image Based Querying",description:"Semantic Image Based Queries Using LangChain (OpenAI) and Redis",page:"/howtos/solutions/vector/image-summary-search",mdxType:"RedisCard"}))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6c272831.f4446c95.js b/assets/js/6c272831.f4446c95.js deleted file mode 100644 index a898875f3f..0000000000 --- a/assets/js/6c272831.f4446c95.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[4936],{71131:(e,i,t)=>{t.d(i,{Z:()=>m});var o=t(67294),s=t(3905),a=t(52195);const r="riContainer_bco2",n="riDescriptionShort_E27B",c="riDetail_wzFs",l="riIcon_yDou",d="riTitle_x6vI",u="riDescription_RDnu",h="riMore_apRP";var p=t(86010);const m=e=>{const[i,t]=o.useState(!1);return o.createElement("a",{href:e.page,className:r},o.createElement("div",{className:n},o.createElement("div",{className:l},o.createElement("span",{className:"fe fe-zap"})),o.createElement("div",{className:c},o.createElement("div",{className:d},o.createElement("a",{href:e.page},e.title)),o.createElement("div",{className:u},e.description,o.Children.count(e.children)>0&&o.createElement("span",{className:(0,p.Z)(h,"fe","fe-more-horizontal"),onClick:()=>t(!i)})))),i&&o.createElement("div",{className:"ri-description-long"},o.createElement(s.Zo,{components:a.Z},e.children)))}},35077:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>l,contentTitle:()=>n,default:()=>h,frontMatter:()=>r,metadata:()=>c,toc:()=>d});var o=t(87462),s=(t(67294),t(3905)),a=t(71131);const r={id:"index-solutions",title:"Solution Tutorials",sidebar_label:"Overview",slug:"/howtos/solutions"},n=void 0,c={unversionedId:"howtos/solutions/index-solutions",id:"howtos/solutions/index-solutions",title:"Solution Tutorials",description:"This page provides a listing of dozens of popular app solution tutorials from Redis.",source:"@site/docs/howtos/solutions/index-solutions.mdx",sourceDirName:"howtos/solutions",slug:"/howtos/solutions",permalink:"/howtos/solutions",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/index-solutions.mdx",tags:[],version:"current",lastUpdatedAt:1693562881,formattedLastUpdatedAt:"Sep 1, 2023",frontMatter:{id:"index-solutions",title:"Solution Tutorials",sidebar_label:"Overview",slug:"/howtos/solutions"},sidebar:"docs",previous:{title:"Cheat sheet",permalink:"/howtos/quick-start/cheat-sheet"},next:{title:"How to Build an E-Commerce App Using Redis with the CQRS Pattern",permalink:"/howtos/solutions/microservices/cqrs"}},l={},d=[{value:"Microservices",id:"microservices",level:2},{value:"Fraud detection",id:"fraud-detection",level:2},{value:"Caching architecture",id:"caching-architecture",level:2},{value:"Real-time Inventory",id:"real-time-inventory",level:2},{value:"Mobile Banking",id:"mobile-banking",level:2},{value:"Vectors",id:"vectors",level:2}],u={toc:d};function h(e){let{components:i,...t}=e;return(0,s.kt)("wrapper",(0,o.Z)({},u,t,{components:i,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"This page provides a listing of dozens of popular app solution tutorials from Redis."),(0,s.kt)("h2",{id:"microservices"},"Microservices"),(0,s.kt)("p",null,"Learn how to easily build, test and deploy code for common microservice and caching design patterns across different industries using Redis."),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"CQRS Pattern",description:"How to build an e-commerce app using Redis with the CQRS Pattern",page:"/howtos/solutions/microservices/cqrs",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Interservice Communication",description:"Microservices Communication with Redis streams",page:"/howtos/solutions/microservices/interservice-communication",mdxType:"RedisCard"}))),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Query Caching Pattern",description:"How to use Redis for Query Caching",page:"/howtos/solutions/microservices/caching",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"API Gateway Caching",description:"How to use Redis for API Gateway Caching",page:"/howtos/solutions/microservices/api-gateway-caching",mdxType:"RedisCard"}))),(0,s.kt)("h2",{id:"fraud-detection"},"Fraud detection"),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Digital Identity Validation",description:"How to Handle Digital Identity Validation Using Redis",page:"/howtos/solutions/fraud-detection/digital-identity-validation",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Transaction Risk Scoring",description:"How to use Redis for Transaction risk scoring",page:"/howtos/solutions/fraud-detection/transaction-risk-scoring",mdxType:"RedisCard"}))),(0,s.kt)("h2",{id:"caching-architecture"},"Caching architecture"),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Write Behind Caching",description:"How to use Redis for Write-behind Caching",page:"/howtos/solutions/caching-architecture/write-behind",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Write Through caching",description:"How to use Redis for Write through caching strategy",page:"/howtos/solutions/caching-architecture/write-through",mdxType:"RedisCard"}))),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Cache Prefetching",description:"How to use Redis for Cache Prefetching Strategy",page:"/howtos/solutions/caching-architecture/cache-prefetching",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Cache Aside (Query Caching)",description:"How to use Redis for Cache-aside",page:"/howtos/solutions/microservices/caching",mdxType:"RedisCard"}))),(0,s.kt)("h2",{id:"real-time-inventory"},"Real-time Inventory"),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Available to Promise",description:"Available to Promise in Real-time Inventory Using Redis",page:"/howtos/solutions/real-time-inventory/available-to-promise",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Real-time Local Inventory Search (GeoSpatial)",description:"Real-time Local Inventory Search Using Redis",page:"/howtos/solutions/real-time-inventory/local-inventory-search",mdxType:"RedisCard"}))),(0,s.kt)("h2",{id:"mobile-banking"},"Mobile Banking"),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Authentication and Session Storage",description:"Mobile Banking Authentication and Session Storage Using Redis",page:"/howtos/solutions/mobile-banking/session-management",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Account Dashboard",description:"Mobile Banking Account Dashboard Using Redis",page:"/howtos/solutions/mobile-banking/account-dashboard",mdxType:"RedisCard"}))),(0,s.kt)("h2",{id:"vectors"},"Vectors"),(0,s.kt)("div",{class:"row"},(0,s.kt)("div",{class:"col"},(0,s.kt)(a.Z,{title:"Vector Similarity Search",description:"Getting Started with Vector Search Using Redis in NodeJS",page:"/howtos/solutions/vector/getting-started-vector",mdxType:"RedisCard"})),(0,s.kt)("div",{class:"col"})))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.06aa9704.js b/assets/js/935f2afb.06aa9704.js new file mode 100644 index 0000000000..dc8c7e1bd4 --- /dev/null +++ b/assets/js/935f2afb.06aa9704.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docs":[{"type":"link","label":"Home","href":"/"},{"type":"link","label":"Getting Started","href":"/howtos/quick-start","docId":"howtos/quick-start/index-quick-start"},{"type":"category","label":"Create","items":[{"type":"link","label":"Overview - All Quick Starts","href":"/create","docId":"create/index-create"},{"type":"link","label":"Redis Functions","href":"/create/redis-functions","docId":"create/redis-functions/index-redis-functions"},{"type":"category","label":"Redis on Azure Cache","items":[{"type":"link","label":"Overview","href":"/create/azure","docId":"create/azure/index-azure"},{"type":"link","label":"Redis on Azure Cache","href":"/create/azure/portal","docId":"create/azure/portal/index-azure-portal"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis on AWS","items":[{"type":"link","label":"Overview","href":"/create/aws","docId":"create/aws/index-aws"},{"type":"link","label":"Redis on AWS","href":"/create/aws/redis-on-aws","docId":"create/aws/redis-on-aws/index-redis-on-aws"},{"type":"link","label":"Building a Slack Bot using AWS S3 and Redis Search and Query Engine","href":"/create/aws/slackbot","docId":"create/aws/slackbot/index-slackbot"},{"type":"link","label":"Deploy and Manage Redis Database on AWS using Terraform","href":"/create/aws/terraform","docId":"create/aws/terraform/index-terraform"},{"type":"link","label":"Building a Real-Time Bidding Platform using NodeJS, AWS Lambda and Redis","href":"/create/aws/bidding-on-aws","docId":"create/aws/bidding-on-aws/index-bidding-on-aws"},{"type":"link","label":"Online Data Migration from AWS Elasticache to Redis","href":"/create/aws/import/database-migration-aws-elasticache-redis-enterprise-cloud/","docId":"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud"},{"type":"link","label":"Building a Real-Time Chat application on AWS using Python and Redis","href":"/create/aws/chatapp","docId":"create/aws/chatapp/index-chatapp"},{"type":"link","label":"Building an Analytics Dashboard using NodeJS, Redis and AWS","href":"/create/aws/analytics-using-aws","docId":"create/aws/analytics-using-aws/index-analytics-using-aws"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis on Docker","items":[{"type":"link","label":"Overview","href":"/create/docker/","docId":"create/docker/index-docker"},{"type":"link","label":"Node.js, Nginx, Redis and Docker","href":"/create/docker/nodejs-nginx-redis","docId":"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis on Kubernetes","items":[{"type":"link","label":"Overview","href":"/create/kubernetes/","docId":"create/kubernetes/index-kubernetes"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Redis on Windows","href":"/create/windows","docId":"create/windows/index-windows"},{"type":"link","label":"Redis using Jenkins","href":"/create/jenkins","docId":"create/jenkins/index-jenkins"},{"type":"category","label":"Redis using Azure Functions","items":[{"type":"link","label":"Getting Started with Azure Functions and Redis","href":"/create/azurefunctions","docId":"create/azurefunctions/index-azurefunctions"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Develop","items":[{"type":"link","label":"Overview","href":"/develop","docId":"develop/index-develop"},{"type":"category","label":"Java","items":[{"type":"link","label":"Overview","href":"/develop/java","docId":"develop/java/index-java"},{"type":"category","label":"Spring","items":[{"type":"link","label":"Overview","href":"/develop/java/spring","docId":"develop/java/spring/index-spring"},{"type":"category","label":"Redis OM Tutorial","items":[{"type":"link","label":"Introduction","href":"/develop/java/spring/redis-om/redis-om-spring","docId":"develop/java/spring/redis-om/redis-om-spring"},{"type":"link","label":"Working with JSON","href":"/develop/java/spring/redis-om/redis-om-spring-json","docId":"develop/java/spring/redis-om/redis-om-spring-json"},{"type":"link","label":"Working with Hashes","href":"/develop/java/spring/redis-om/redis-om-spring-hash","docId":"develop/java/spring/redis-om/redis-om-spring-hash"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis and Spring Course","items":[{"type":"link","label":"Overview","href":"/develop/java/redis-and-spring-course","docId":"develop/java/spring/redis-and-spring-course/index-redis-and-spring-course"},{"type":"link","label":"Up and Running","href":"/develop/java/redis-and-spring-course/lesson_1","docId":"develop/java/spring/redis-and-spring-course/lesson_1/index-lesson_1"},{"type":"link","label":"Spring Data Redis","href":"/develop/java/redis-and-spring-course/lesson_2","docId":"develop/java/spring/redis-and-spring-course/lesson_2/index-lesson_2"},{"type":"link","label":"Mapping & Repositories","href":"/develop/java/redis-and-spring-course/lesson_3","docId":"develop/java/spring/redis-and-spring-course/lesson_3/index-lesson_3"},{"type":"link","label":"User Roles & Secondary Indexes","href":"/develop/java/redis-and-spring-course/lesson_4","docId":"develop/java/spring/redis-and-spring-course/lesson_4/index-lesson_4"},{"type":"link","label":"Books, Categories & The Catalog","href":"/develop/java/redis-and-spring-course/lesson_5","docId":"develop/java/spring/redis-and-spring-course/lesson_5/index-lesson_5"},{"type":"link","label":"Domain Models w/ Redis","href":"/develop/java/redis-and-spring-course/lesson_6","docId":"develop/java/spring/redis-and-spring-course/lesson_6/index-lesson_6"},{"type":"link","label":"Search w/ Redis","href":"/develop/java/redis-and-spring-course/lesson_7","docId":"develop/java/spring/redis-and-spring-course/lesson_7/index-lesson_7"},{"type":"link","label":"Caching w/ Redis","href":"/develop/java/redis-and-spring-course/lesson_9","docId":"develop/java/spring/redis-and-spring-course/lesson_9/index-lesson_9"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Rate Limiting","items":[{"type":"link","label":"Overview","href":"/develop/java/spring/rate-limiting","docId":"develop/java/spring/rate-limiting/index-ratelimiting"},{"type":"category","label":"Fixed Window","items":[{"type":"link","label":"Overview","href":"/develop/java/spring/rate-limiting/fixed-window","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window"},{"type":"link","label":"Reactive Implementation","href":"/develop/java/spring/rate-limiting/fixed-window/reactive","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive"},{"type":"link","label":"Atomicity with Lua","href":"/develop/java/spring/rate-limiting/fixed-window/reactive-lua","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive-lua"},{"type":"link","label":"Atomicity with Gears","href":"/develop/java/spring/rate-limiting/fixed-window/reactive-gears","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive-gears"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"C","href":"/develop/C/","docId":"develop/C/index-c"},{"type":"category","label":"Node.js","items":[{"type":"link","label":"Overview","href":"/develop/node","docId":"develop/node/index-node"},{"type":"link","label":"Getting Started","href":"/develop/node/gettingstarted","docId":"develop/node/gettingstarted/index-gettingstarted"},{"type":"category","label":"Node.js Crash Course","items":[{"type":"link","label":"Overview","href":"/develop/node/node-crash-course","docId":"develop/node/node-crash-course/index-node-crash-course"},{"type":"link","label":"Welcome","href":"/develop/node/nodecrashcourse/welcome","docId":"develop/node/node-crash-course/welcome/index-welcome"},{"type":"link","label":"What is Redis?","href":"/develop/node/nodecrashcourse/whatisredis","docId":"develop/node/node-crash-course/whatisredis/index-whatisredis"},{"type":"link","label":"Redis and Node.js","href":"/develop/node/nodecrashcourse/redisandnodejs","docId":"develop/node/node-crash-course/redisandnodejs/index-redisandnodejs"},{"type":"link","label":"Introducing RedisInsight","href":"/develop/node/nodecrashcourse/introducingredisinsight","docId":"develop/node/node-crash-course/introducingredisinsight/index-introducingredisinsight"},{"type":"link","label":"Sample Application Overview","href":"/develop/node/nodecrashcourse/sampleapplicationoverview","docId":"develop/node/node-crash-course/sampleapplicationoverview/index-sampleapplicationoverview"},{"type":"link","label":"Running the Application","href":"/develop/node/nodecrashcourse/runningtheapplication","docId":"develop/node/node-crash-course/runningtheapplication/index-runningtheapplication"},{"type":"link","label":"Domain Objects with Hashes","href":"/develop/node/nodecrashcourse/domainobjectswithhashes","docId":"develop/node/node-crash-course/domainobjectswithhashes/index-domainobjectswithhashes"},{"type":"link","label":"Redis Extensibility","href":"/develop/node/nodecrashcourse/introductiontomodules","docId":"develop/node/node-crash-course/introductiontomodules/index-introductiontomodules"},{"type":"link","label":"JSON","href":"/develop/node/nodecrashcourse/redisjson","docId":"develop/node/node-crash-course/redisjson/index-redisjson"},{"type":"link","label":"Searching and Querying","href":"/develop/node/nodecrashcourse/redisearch","docId":"develop/node/node-crash-course/redisearch/index-redisearch"},{"type":"link","label":"Checkins with Streams","href":"/develop/node/nodecrashcourse/checkinswithstreams","docId":"develop/node/node-crash-course/checkinswithstreams/index-checkinswithstreams"},{"type":"link","label":"Managing Success","href":"/develop/node/nodecrashcourse/managingsuccess","docId":"develop/node/node-crash-course/managingsuccess/index-managingsuccess"},{"type":"link","label":"Caching","href":"/develop/node/nodecrashcourse/caching","docId":"develop/node/node-crash-course/caching/index-caching"},{"type":"link","label":"Session Storage","href":"/develop/node/nodecrashcourse/sessionstorage","docId":"develop/node/node-crash-course/sessionstorage/index-sessionstorage"},{"type":"link","label":"Advanced Streams","href":"/develop/node/nodecrashcourse/advancedstreams","docId":"develop/node/node-crash-course/advancedstreams/index-advancedstreams"},{"type":"link","label":"Probabilistic Data Structures","href":"/develop/node/nodecrashcourse/redisbloom","docId":"develop/node/node-crash-course/redisbloom/index-redisbloom"},{"type":"link","label":"Wrap Up","href":"/develop/node/nodecrashcourse/coursewrapup","docId":"develop/node/node-crash-course/coursewrapup/index-coursewrapup"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Redis OM for Node.js","href":"/develop/node/redis-om","docId":"develop/node/redis-om/index-redis-om"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Python","items":[{"type":"link","label":"Redis with FastAPI","href":"/develop/python/fastapi","docId":"develop/python/fastapi/index-fastapi"}],"collapsed":true,"collapsible":true},{"type":"category","label":".NET","items":[{"type":"category","label":"ASP.NET Core","items":[{"type":"category","label":"Rate Limiting","items":[{"type":"link","label":"Fixed Window Rate Limiting app using ASP.NET","href":"/develop/dotnet/aspnetcore/rate-limiting/fixed-window","docId":"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting"},{"type":"link","label":"Sliding Window Rate Limiting app using ASP.NET","href":"/develop/dotnet/aspnetcore/rate-limiting/sliding-window","docId":"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting"},{"type":"link","label":"Rate Limiting Middleware","href":"/develop/dotnet/aspnetcore/rate-limiting/middleware","docId":"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Caching","items":[{"type":"link","label":"Basic API Caching using ASP.NET Core","href":"/develop/dotnet/aspnetcore/caching/basic-api-caching","docId":"develop/dotnet/aspnetcore/caching/basic/index-basic-caching"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis OM Dotnet","items":[{"type":"link","label":"Add and Retrieve Objects","href":"/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects","docId":"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects"},{"type":"link","label":"Creating an Index","href":"/develop/dotnet/redis-om-dotnet/searching/creating-an-index","docId":"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index"},{"type":"category","label":"Querying","items":[{"type":"link","label":"Simple Text Queries","href":"/develop/dotnet/redis-om-dotnet/simple-text-queries","docId":"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries"},{"type":"link","label":"Numeric Queries","href":"/develop/dotnet/redis-om-dotnet/searching/numeric-queries","docId":"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries"},{"type":"link","label":"Geo Filters","href":"/develop/dotnet/redis-om-dotnet/searching/geo-filters","docId":"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Aggregations","items":[{"type":"link","label":"Aggregations Intro","href":"/develop/dotnet/redis-om-dotnet/aggregations","docId":"develop/dotnet/redis-om-dotnet/aggregations/intro/intro"},{"type":"link","label":"Apply Functions","href":"/develop/dotnet/redis-om-dotnet/aggregations/apply-functions","docId":"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions"},{"type":"link","label":"Grouping and Reductions","href":"/develop/dotnet/redis-om-dotnet/aggregations/groups/groups","docId":"develop/dotnet/redis-om-dotnet/aggregations/groups/groups"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Streams","items":[{"type":"link","label":"Using Redis Streams with .NET","href":"/develop/dotnet/streams/stream-basics","docId":"develop/dotnet/streams/stream-basics"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"Ruby","href":"/develop/ruby/","docId":"develop/ruby/index-ruby"},{"type":"link","label":"PHP","href":"/develop/php/","docId":"develop/php/index-php"},{"type":"link","label":"Deno","href":"/develop/deno/","docId":"develop/deno/index-deno"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Explore","items":[{"type":"link","label":"Overview","href":"/explore","docId":"explore/index-explore"},{"type":"link","label":"Import Data into a Redis database","href":"/explore/import/","docId":"explore/import/index-import"},{"type":"link","label":"Redis Data Source for Grafana","href":"/explore/redisdatasource","docId":"explore/redisdatasource/index-redisdatasource"},{"type":"link","label":"Redis Enterprise Observability with Datadog","href":"/explore/datadog","docId":"explore/datadog/index-datadog"},{"type":"link","label":"RIOT","href":"/explore/riot","docId":"explore/riot/index-riot"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Operate","items":[{"type":"category","label":"Observability","items":[{"type":"link","label":"Redis Data Source for Grafana","href":"/operate/observability/redisdatasource","docId":"operate/observability/redisdatasource/index-redisdatasource"},{"type":"link","label":"Redis Enterprise Observability with Datadog","href":"/operate/observability/datadog","docId":"operate/observability/datadog/index-datadog"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Provisioning","items":[{"type":"link","label":"Deploy and Manage Redis Database on AWS using Terraform","href":"/operate/provisioning/terraform","docId":"operate/provisioning/terraform/index-terraform"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Running Redis at Scale","items":[{"type":"link","label":"Overview","href":"/operate/redis-at-scale","docId":"operate/redis-at-scale/index-redis-at-scale"},{"type":"category","label":"1 Talking to Redis","items":[{"type":"link","label":"1.0 Redis Server Overview","href":"/operate/redis-at-scale/talking-to-redis/redis-server-overview","docId":"operate/redis-at-scale/talking-to-redis/redis-server-overview/index-redis-server-overview"},{"type":"link","label":"1.1 The Command Line Tool: Redis-CLI","href":"/operate/redis-at-scale/talking-to-redis/command-line-tool","docId":"operate/redis-at-scale/talking-to-redis/command-line-tool/index-command-line-tool"},{"type":"link","label":"1.2 Configuring a Redis Server","href":"/operate/redis-at-scale/talking-to-redis/configuring-a-redis-server","docId":"operate/redis-at-scale/talking-to-redis/configuring-a-redis-server/index-configuring-a-redis-server"},{"type":"link","label":"1.3 Redis Clients","href":"/operate/redis-at-scale/talking-to-redis/redis-clients","docId":"operate/redis-at-scale/talking-to-redis/redis-clients/index-redis-clients"},{"type":"link","label":"1.4 Client Performance Improvements","href":"/operate/redis-at-scale/talking-to-redis/client-performance-improvements","docId":"operate/redis-at-scale/talking-to-redis/client-performance-improvements/index-client-performance-improvements"},{"type":"link","label":"1.5 Initial Tuning","href":"/operate/redis-at-scale/talking-to-redis/initial-tuning","docId":"operate/redis-at-scale/talking-to-redis/initial-tuning/index-initial-tuning"}],"collapsed":true,"collapsible":true},{"type":"category","label":"2 Persistence & Durability","items":[{"type":"link","label":"2.0 Introduction to Persistence and Durability\'","href":"/operate/redis-at-scale/persistence-and-durability/introduction","docId":"operate/redis-at-scale/persistence-and-durability/introduction/index-introduction"},{"type":"link","label":"2.1 Persistence options in Redis\'","href":"/operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis","docId":"operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis/index-persistence-options-in-redis"},{"type":"link","label":"2.2 Exercise: Saving a Snapshot","href":"/operate/redis-at-scale/persistence-and-durability/exercise","docId":"operate/redis-at-scale/persistence-and-durability/exercise/index-exercise"}],"collapsed":true,"collapsible":true},{"type":"category","label":"3 High Availability","items":[{"type":"link","label":"3.0 Introduction to High Availability","href":"/operate/redis-at-scale/high-availability/introduction","docId":"operate/redis-at-scale/high-availability/introduction/index-introduction"},{"type":"link","label":"3.1 Basic Replication","href":"/operate/redis-at-scale/high-availability/basic-replication","docId":"operate/redis-at-scale/high-availability/basic-replication/index-basic-replication"},{"type":"link","label":"3.2 Exercise - Enabling Basic Replication","href":"/operate/redis-at-scale/high-availability/exercise-1","docId":"operate/redis-at-scale/high-availability/exercise-1/index-exercise-1"},{"type":"link","label":"3.3 Understanding Sentinels","href":"/operate/redis-at-scale/high-availability/understanding-sentinels","docId":"operate/redis-at-scale/high-availability/understanding-sentinels/index-understanding-sentinels"},{"type":"link","label":"3.4 Exercise - Sentinel Hands-on","href":"/operate/redis-at-scale/high-availability/exercise-2","docId":"operate/redis-at-scale/high-availability/exercise-2/index-exercise-2"}],"collapsed":true,"collapsible":true},{"type":"category","label":"4 Scalability","items":[{"type":"link","label":"4.0 Clustering In Redis","href":"/operate/redis-at-scale/scalability/lustering-in-redis","docId":"operate/redis-at-scale/scalability/clustering-in-redis/index-clustering-in-redis"},{"type":"link","label":"4.1 Exercise - Creating a Redis Cluster","href":"/operate/redis-at-scale/scalability/exercise-1","docId":"operate/redis-at-scale/scalability/exercise-1/index-exercise-1"},{"type":"link","label":"4.2 Using Redis-CLI with a Redis Cluster","href":"/operate/redis-at-scale/scalability/redis-cli-with-redis-cluster","docId":"operate/redis-at-scale/scalability/redis-cli-with-redis-cluster/index-redis-cli-with-redis-cluster"},{"type":"link","label":"4.3 Redis Cluster and Client Libraries","href":"/operate/redis-at-scale/scalability/redis-cluster-and-client-libraries","docId":"operate/redis-at-scale/scalability/redis-cluster-and-client-libraries/index-redis-cluster-and-client-libraries"}],"collapsed":true,"collapsible":true},{"type":"category","label":"5 Observability","items":[{"type":"link","label":"5.0 Introduction to Observability","href":"/operate/redis-at-scale/observability/introduction","docId":"operate/redis-at-scale/observability/introduction/index-introduction"},{"type":"link","label":"5.1 Data points in Redis","href":"/operate/redis-at-scale/observability/data-points-in-redis","docId":"operate/redis-at-scale/observability/data-points-in-redis/index-data-points-in-redis"},{"type":"link","label":"5.2 Getting Redis Statistics","href":"/operate/redis-at-scale/observability/exercise-1","docId":"operate/redis-at-scale/observability/exercise-1/index-exercise-1"},{"type":"link","label":"5.3 Identifying Issues","href":"/operate/redis-at-scale/observability/identifying-issues","docId":"operate/redis-at-scale/observability/identifying-issues/index-identifying-issues"}],"collapsed":true,"collapsible":true},{"type":"category","label":"6 Course wrap-up","items":[{"type":"link","label":"Course Wrap-up","href":"/operate/redis-at-scale/course-wrap-up/","docId":"operate/redis-at-scale/course-wrap-up/index-wrap-up"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Orchestration","items":[{"type":"link","label":"Overview","href":"/operate/orchestration","docId":"operate/orchestration/index-orchestration"},{"type":"link","label":"Redis on Docker","href":"/operate/orchestration/docker/","docId":"operate/orchestration/docker/index-docker"},{"type":"link","label":"Node.js, Nginx, Redis and Docker","href":"/operate/docker/nodejs-nginx-redis","docId":"operate/orchestration/nodejs-nginx-redis/index-nodejs-nginx-redis"},{"type":"link","label":"Redis on Kubernetes","href":"/operate/orchestration/kubernetes/kubernetes-gke","docId":"operate/orchestration/kubernetes-gke/index-kubernetes-gke"},{"type":"link","label":"Kubernetes Operator: What It Is and Why You Should Really Care About It","href":"/operate/orchestration/kubernetes-operator","docId":"operate/orchestration/kubernetes-operator/index-kubernetes-operator"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"HowTos & Tutorials","items":[{"type":"link","label":"Cheat sheet","href":"/howtos/quick-start/cheat-sheet","docId":"howtos/quick-start/cheat-sheets/index-quick-start-cheat-sheet"},{"type":"category","label":"Solutions","items":[{"type":"link","label":"Overview","href":"/howtos/solutions","docId":"howtos/solutions/index-solutions"},{"type":"category","label":"Microservices","items":[{"type":"link","label":"How to Build an E-Commerce App Using Redis with the CQRS Pattern","href":"/howtos/solutions/microservices/cqrs","docId":"howtos/solutions/microservices/cqrs/index-solutions-cqrs"},{"type":"link","label":"Microservices Communication with Redis Streams","href":"/howtos/solutions/microservices/interservice-communication","docId":"howtos/solutions/microservices/interservice-communication/index-solutions-interservice-communication"},{"type":"link","label":"How to use Redis for Query Caching","href":"/howtos/solutions/microservices/caching","docId":"howtos/solutions/microservices/caching/index-solutions-caching"},{"type":"link","label":"How to use Redis for API Gateway Caching","href":"/howtos/solutions/microservices/api-gateway-caching","docId":"howtos/solutions/microservices/api-gateway-caching/index-solutions-api-gateway-caching"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Fraud detection","items":[{"type":"link","label":"Redis for Digital Identity Validation","href":"/howtos/solutions/fraud-detection/digital-identity-validation","docId":"howtos/solutions/fraud-detection/digital-identity-validation/index-digital-identity-validation"},{"type":"link","label":"How to use Redis for Transaction risk scoring","href":"/howtos/solutions/fraud-detection/transaction-risk-scoring","docId":"howtos/solutions/fraud-detection/transaction-risk-scoring/index-transaction-risk-scoring"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Caching architecture","items":[{"type":"link","label":"How to use Redis for Write-behind Caching","href":"/howtos/solutions/caching-architecture/write-behind","docId":"howtos/solutions/caching-architecture/write-behind/index-write-behind"},{"type":"link","label":"How to use Redis for Write through caching strategy","href":"/howtos/solutions/caching-architecture/write-through","docId":"howtos/solutions/caching-architecture/write-through/index-write-through"},{"type":"link","label":"How to use Redis for Cache Prefetching Strategy","href":"/howtos/solutions/caching-architecture/cache-prefetching","docId":"howtos/solutions/caching-architecture/cache-prefetching/index-cache-prefetching"},{"type":"link","label":"How to use Redis for Query Caching","href":"/howtos/solutions/microservices/caching","docId":"howtos/solutions/microservices/caching/index-solutions-caching"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Real-time Inventory","items":[{"type":"link","label":"Available to Promise in Real-time Inventory","href":"/howtos/solutions/real-time-inventory/available-to-promise","docId":"howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise"},{"type":"link","label":"Real-time Local Inventory Search Using Redis","href":"/howtos/solutions/real-time-inventory/local-inventory-search","docId":"howtos/solutions/real-time-inventory/local-inventory-search/index-rti-local-inventory-search"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Mobile Banking","items":[{"type":"link","label":"Mobile Banking Authentication and Session Storage Using Redis","href":"/howtos/solutions/mobile-banking/session-management","docId":"howtos/solutions/mobile-banking/session-management/index-mb-session-management"},{"type":"link","label":"Mobile Banking Account Dashboard Using Redis","href":"/howtos/solutions/mobile-banking/account-dashboard","docId":"howtos/solutions/mobile-banking/account-dashboard/index-mb-account-dashboard"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Vector Database","items":[{"type":"link","label":"How to Perform Vector Similarity Search Using Redis in NodeJS","href":"/howtos/solutions/vector/getting-started-vector","docId":"howtos/solutions/vector/getting-started-vector/index-getting-started-vector"},{"type":"link","label":"How to Build a GenAI Chatbot Using LangChain and Redis","href":"/howtos/solutions/vector/gen-ai-chatbot","docId":"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot"},{"type":"link","label":"Semantic Text Search Using LangChain (OpenAI) and Redis","href":"/howtos/solutions/vector/semantic-text-search","docId":"howtos/solutions/vector/semantic-text-search/index-semantic-text-search"},{"type":"link","label":"Semantic Image Based Queries Using LangChain (OpenAI) and Redis","href":"/howtos/solutions/vector/image-summary-search","docId":"howtos/solutions/vector/image-summary-search/index-image-summary-search"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"How to build a Real-Time Leaderboard app Using Redis","href":"/howtos/leaderboard","docId":"howtos/leaderboard/index-leaderboard"},{"type":"link","label":"How to build a Rate Limiter using Redis","href":"/howtos/ratelimiting","docId":"howtos/ratelimiting/index-ratelimiting"},{"type":"link","label":"How to cache REST API responses Using Redis & NodeJS","href":"/howtos/caching","docId":"howtos/caching/index-caching"},{"type":"category","label":"How to list & search Movies database using Redis Stack","items":[{"type":"link","label":"2. Install Redis Stack","href":"/howtos/moviesdatabase/install","docId":"howtos/moviesdatabase/install/index-install"},{"type":"link","label":"3. Create Index","href":"/howtos/moviesdatabase/create","docId":"howtos/moviesdatabase/create/index-create"},{"type":"link","label":"4. Query Data","href":"/howtos/moviesdatabase/query","docId":"howtos/moviesdatabase/query/index-query"},{"type":"link","label":"5. Manage Index","href":"/howtos/moviesdatabase/manage","docId":"howtos/moviesdatabase/manage/index-manage"},{"type":"link","label":"6. Import datasets","href":"/howtos/moviesdatabase/import","docId":"howtos/moviesdatabase/import/index-import"},{"type":"link","label":"7. Query Movies","href":"/howtos/moviesdatabase/querymovies","docId":"howtos/moviesdatabase/querymovies/index-querymovies"},{"type":"link","label":"8. Aggregation","href":"/howtos/moviesdatabase/aggregation","docId":"howtos/moviesdatabase/aggregation/index-aggregation"},{"type":"link","label":"9. Advanced Option","href":"/howtos/moviesdatabase/advancedoption","docId":"howtos/moviesdatabase/advancedoption/index-advancedoption"},{"type":"link","label":"10. Sample Application","href":"/howtos/moviesdatabase/sampleapp","docId":"howtos/moviesdatabase/sampleapp/index-sampleapp"}],"collapsed":true,"collapsible":true},{"type":"link","label":"How to build a Chat application using Redis","href":"/howtos/chatapp","docId":"howtos/chatapp/index-chatapp"},{"type":"link","label":"How to build a Fraud Detection System using Redis","href":"/howtos/frauddetection","docId":"howtos/frauddetection/index-frauddetection"},{"type":"link","label":"Building a Pipeline for Natural Language Processing using RedisGears","href":"/howtos/nlp","docId":"howtos/nlp/index-nlp"},{"type":"link","label":"Benchmarks for BERT Large Question Answering inference for RedisAI and RedisGears","href":"/howtos/redisai/bert-qa-benchmarking-with-redisai-and-redisgears","docId":"howtos/bert-qa-benchmarking/bert-qa-benchmarking-with-redisai-and-redisgears"},{"type":"link","label":"How to build a HackerNews Clone using Redis","href":"/howtos/hackernews","docId":"howtos/hackernews/index-hackernews"},{"type":"link","label":"Redis Anti-Patterns Every Developer Should Avoid","href":"/howtos/antipatterns/","docId":"howtos/antipatterns/index-antipatterns"},{"type":"link","label":"Building a Social Network Application using Redis Stack","href":"/howtos/socialnetwork/","docId":"howtos/socialnetwork/index-socialnetwork"},{"type":"link","label":"How to Use SSL/TLS With Redis Enterprise","href":"/howtos/security/","docId":"howtos/security/index-tls"},{"type":"link","label":"Building an Analytics dashboard app using Redis","href":"/howtos/analytics","docId":"howtos/analytics/index-analytics"},{"type":"link","label":"Building a Popup Store application using Redis","href":"/howtos/popupstore","docId":"howtos/popupstore/index-popupstore"},{"type":"link","label":"How to build a NodeJS based application on Heroku using Redis","href":"/howtos/herokunodejs","docId":"howtos/herokunodejs/index-herokunodejs"},{"type":"link","label":"How to build a Python based application on Heroku using Redis","href":"/howtos/herokupython","docId":"howtos/herokupython/index-herokupython"},{"type":"link","label":"How to build a Java based application on Heroku using Redis","href":"/howtos/herokujava","docId":"howtos/herokujava/index-herokujava"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Get Involved","items":[{"type":"link","label":"Overview","href":"/community/","docId":"get-involved/index-getinvolved"},{"type":"link","label":"Discord","href":"/community/discord/","docId":"get-involved/discord/index-discord"},{"type":"link","label":"Redis Live","href":"/redis-live/","docId":"get-involved/redis-live/index-redis-live"},{"type":"category","label":"Redis Insiders","items":[{"type":"link","label":"Redis Insiders","href":"/redis-insiders/","docId":"get-involved/redis-insiders/index-redis-insiders"},{"type":"link","label":"Jyotsna Gupta","href":"/redis-insiders/jyotsna-gupta/","docId":"get-involved/redis-insiders/jyotsna-gupta/index-jyotsna-gupta"},{"type":"link","label":"Moiz Kapasi","href":"/redis-insiders/moiz-kapasi/","docId":"get-involved/redis-insiders/moiz-kapasi/index-moiz-kapasi"},{"type":"link","label":"Michael Owolabi","href":"/redis-insiders/michael-owolabi/","docId":"get-involved/redis-insiders/michael-owolabi/index-michael-owolabi"},{"type":"link","label":"Stevan Thomas","href":"/redis-insiders/stevan-thomas/","docId":"get-involved/redis-insiders/stevan-thomas/index-stevan-thomas"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacktoberfest 2021","items":[{"type":"link","label":"Start Here","href":"/hacktoberfest/","docId":"get-involved/hacktoberfest/index-hacktoberfest"},{"type":"link","label":"Lara\'s Hacktoberfest at Redis Story","href":"/hacktoberfest/stories/lara-aasem","docId":"get-involved/hacktoberfest/lara-aasem-story/index-lara-aasem-story"},{"type":"link","label":"Vincent\'s Hacktoberfest at Redis Story","href":"/hacktoberfest/stories/vincent-aceto","docId":"get-involved/hacktoberfest/vincent-aceto-story/index-vincent-aceto-story"}],"collapsed":true,"collapsible":true},{"type":"link","label":"DEVcember","href":"/devcember/","docId":"get-involved/devcember/index-devcember"}],"collapsed":true,"collapsible":true},{"type":"category","label":"E-books","items":[{"type":"link","label":"NoSQL Data Modeling Patterns","href":"/ebooks/8-nosql-data-modeling-patterns","docId":"ebooks/nosql-data-modeling-patterns"},{"type":"link","label":"3 design patterns to speed up MEAN and MERN stack applications","href":"/ebooks/three-caching-design-patterns","docId":"ebooks/three-caching-design-patterns"}],"collapsed":true,"collapsible":true}]},"docs":{"create/aws/analytics-using-aws/index-analytics-using-aws":{"id":"create/aws/analytics-using-aws/index-analytics-using-aws","title":"How to Build and Deploy Your Own Analytics Dashboard using NodeJS and Redis on the AWS Platform","description":"An interactive analytics dashboard serves several purposes. They allow you to share data and provide you with all those vital information to make game-changing decisions at a faster pace. Building a real-time dynamic dashboard using a traditional relational database might require a complex set of queries. By using a NoSQL database like Redis, you can build a powerful interactive and dynamic dashboard with a small number of Redis commands.","sidebar":"docs"},"create/aws/bidding-on-aws/index-bidding-on-aws":{"id":"create/aws/bidding-on-aws/index-bidding-on-aws","title":"How to Build a Real-Time Bidding Platform using NodeJS, AWS Lambda and Redis","description":"Digital technology has propelled us forward to an exciting new era and has transformed almost every aspect of life. We\u2019re more interconnected than ever as communication has become instant. Working from home has now become the norm, helping us pivot to a new way of working during the pandemic. And our ability to reduce carbon emissions by attending work-related events online has meant that we\u2019ve taken greater strides to combat global warming. Continuing this trend is Shamshir Anees and his team, who have created an application that can host digital auctions. By using Redis, data transmission between components was carried out with maximum efficiency, providing users with real-time bidding updates on the dashboard.","sidebar":"docs"},"create/aws/chatapp/index-chatapp":{"id":"create/aws/chatapp/index-chatapp","title":"How to Build a Real Time Chat application on Amazon Web Services using Python and Redis","description":"Real time chat messaging apps are surging in popularity exponentially. Mobile apps like WhatsApp, Facebook, Telegram, Slack, Discord have become \u201ca part and parcel\u201d of our life. Users are addicted to these live chat mobile app conversations as they bring a personal touch and offer a real-time interaction","sidebar":"docs"},"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud":{"id":"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud","title":"How to migrate your database from AWS ElastiCache to Redis without any downtime","description":"Most of the database migration tools available today are offline in nature. They are complex and require manual intervention.","sidebar":"docs"},"create/aws/index-aws":{"id":"create/aws/index-aws","title":"Overview","description":"The following links provide you with the available options to run apps on AWS using Redis:","sidebar":"docs"},"create/aws/README":{"id":"create/aws/README","title":"images","description":""},"create/aws/redis-on-aws/images/README":{"id":"create/aws/redis-on-aws/images/README","title":"images","description":""},"create/aws/redis-on-aws/index-redis-on-aws":{"id":"create/aws/redis-on-aws/index-redis-on-aws","title":"Create Redis database on AWS","description":"Redis Cloud on AWS is fully managed Redis as a service. Designed for modern distributed applications, Redis Cloud on AWS is known for its high performance, infinite scalability and true high availability.","sidebar":"docs"},"create/aws/redis-on-aws/README":{"id":"create/aws/redis-on-aws/README","title":"images","description":""},"create/aws/slackbot/index-slackbot":{"id":"create/aws/slackbot/index-slackbot","title":"How to Build a Slack Bot to Retrieve Lost Files Using AWS S3 and Redis Search and Query Engine","description":"alt_text","sidebar":"docs"},"create/aws/terraform/index-terraform":{"id":"create/aws/terraform/index-terraform","title":"How to Deploy and Manage Redis Database on AWS Using Terraform","description":"terraform","sidebar":"docs"},"create/azure/index-azure":{"id":"create/azure/index-azure","title":"Azure Cache for Redis","description":"The following links provides you with the available options for create instances of Azure Cache for Redis","sidebar":"docs"},"create/azure/portal/index-azure-portal":{"id":"create/azure/portal/index-azure-portal","title":"Create Redis database on Azure Cache","description":"Redis is an open source, in-memory, key-value data store most commonly used as a primary database, cache, message broker, and queue. Redis cache delivers sub-millisecond response times, enabling fast and powerful real-time applications in industries such as gaming, fintech, ad-tech, social media, healthcare, and IoT. Developers love Redis due to its speed, simplicity and performance.","sidebar":"docs"},"create/azurefunctions/index-azurefunctions":{"id":"create/azurefunctions/index-azurefunctions","title":"Getting Started with Azure Functions and Redis","description":"alttext","sidebar":"docs"},"create/cloud/aws/index-aws":{"id":"create/cloud/aws/index-aws","title":"Create Database using AWS Cloud","description":"Redis Cloud on AWS is fully managed Redis as a service. Designed for modern distributed applications, Redis Cloud on AWS is known for its high performance, infinite scalability and true high availability."},"create/cloud/azure/index-azure":{"id":"create/cloud/azure/index-azure","title":"Create Database using Azure Cache for Redis","description":"Azure Cache for Redis is a native fully-managed service on Microsoft Azure. Azure Cache for Redis offers both the Redis open-source (OSS Redis) and a commercial product from Redis (Redis Cloud) as a managed service. It provides secure and dedicated Redis server instances and full Redis API compatibility. The service is operated by Microsoft, hosted on Azure, and accessible to any application within or outside of Azure."},"create/cloud/gcp/index-gcp":{"id":"create/cloud/gcp/index-gcp","title":"Create Database using Google Cloud","description":"Redis Cloud delivers fully managed Redis as a service. It offers all the capabilities of Redis Enterprise while taking care of all the operational aspects associated with operating Redis in the most efficient manner on Google Cloud Platform. Redis Cloud is built on a complete serverless concept, so users don\u2019t need to deal with nodes and clusters"},"create/cloud/images/README":{"id":"create/cloud/images/README","title":"images","description":""},"create/cloud/index-cloud":{"id":"create/cloud/index-cloud","title":"Create Database using Cloud","description":""},"create/cloud/rediscloud/images/README":{"id":"create/cloud/rediscloud/images/README","title":"images","description":""},"create/cloud/rediscloud/index-rediscloud":{"id":"create/cloud/rediscloud/index-rediscloud","title":"Create Database using Redis Cloud","description":"Redis Cloud is a fully managed cloud service by Redis. Built for modern distributed applications, Redis Cloud enables you to run any query, simple or complex, at sub-millisecond performance at virtually infinite scale without worrying about operational complexity or service availability. With modern probabilistic data structures and extensible data models, including Search, JSON, Graph, and Time Series, you can rely on Redis as your data-platform for all your real-time needs."},"create/docker/index-docker":{"id":"create/docker/index-docker","title":"Overview","description":"The following links provide you with the available options to create a new Redis database using Docker","sidebar":"docs"},"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis":{"id":"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis","title":"How to build and run a Node.js application using Nginx, Docker and Redis","description":"Thanks to Node.js - Millions of frontend developers that write JavaScript for the browser are now able to write the server-side code in addition to the client-side code without the need to learn a completely different language. Node.js is a free, open-sourced, cross-platform JavaScript run-time environment. It is capable to handle thousands of concurrent connections with a single server without introducing the burden of managing thread concurrency, which could be a significant source of bugs.","sidebar":"docs"},"create/heroku/index-heroku":{"id":"create/heroku/index-heroku","title":"Overview","description":"The following links provide you with the available options to run apps on Heroku using Redis:"},"create/heroku/portal/index-heroku-portal":{"id":"create/heroku/portal/index-heroku-portal","title":"Create a Redis database on Heroku","description":"Heroku is a cloud Platform as a Service (PaaS) supporting multiple programming languages that is used as a web application deployment model. Heroku lets the developer build, run and scale applications in a similar manner across all the languages(Java, Node.js, Scala, Clojure, Python, PHP, Ruby and Go)."},"create/images/README":{"id":"create/images/README","title":"images","description":""},"create/index-create":{"id":"create/index-create","title":"Create a Redis Database - Quick Starts","description":"The following quick starts shows various ways of how to get started and create a new Redis database:","sidebar":"docs"},"create/jenkins/index-jenkins":{"id":"create/jenkins/index-jenkins","title":"How to Deploy a Redis Enterprise Database from a Jenkins Pipeline","description":"Jenkins is currently the most popular CI(Continuous Integration) tool, with ~15M users. It is an open source automation server which enables developers to reliably build, test, and deploy their software. It was forked in 2011 from a project called Hudson after a dispute with Oracle, and is used for Continuous Integration and Continuous Delivery (CI/CD) and test automation. Jenkins is based on Java and provides over 1700 plugins to automate your developer workflow and save a lot of your time in executing your repetitive tasks.","sidebar":"docs"},"create/kubernetes/index-kubernetes":{"id":"create/kubernetes/index-kubernetes","title":"Overview","description":"The following links provide you with the available options to create a new Redis database on Kubernetes Platforms","sidebar":"docs"},"create/kubernetes/kubernetes-operator/index-kubernetes-operator":{"id":"create/kubernetes/kubernetes-operator/index-kubernetes-operator","title":"Kubernetes Operator: What It Is and Why You Should Really Care About It","description":"My Image"},"create/openshift/index-openshift":{"id":"create/openshift/index-openshift","title":"How to deploy Redis Enterprise on Red Hat OpenShift Container Platform via OperatorHub","description":"Deploying and managing containerized applications is not easy. The rise of microservice architecture has made it cumbersome to deploy containers across multiple environments. Given that containers can be spun up in seconds and at a much higher volume compared to VMs, managing containers across multiple platforms can be extremely challenging."},"create/redis-functions/index-redis-functions":{"id":"create/redis-functions/index-redis-functions","title":"Getting started with Redis Functions","description":"The most impactful addition to Redis version 7.0 is Redis Functions - a new programmability option, improving on scripts by adding modularity, reusability, and better overall developer experience.","sidebar":"docs"},"create/windows/index-windows":{"id":"create/windows/index-windows","title":"How to Install Redis on Windows","description":"You can run Redis on Windows 10 using Windows Subsystem for Linux(a.k.a WSL2). WSL2 is a compatibility layer for running Linux binary executables natively on Windows 10 and Windows Server 2019. WSL2 lets developers run a GNU/Linux environment (that includes command-line tools, utilities, and applications) directly on Windows.","sidebar":"docs"},"develop/C/index-c":{"id":"develop/C/index-c","title":"C and Redis","description":"Find tutorials, examples and technical articles that will help you to develop with Redis and C.","sidebar":"docs"},"develop/deno/index-deno":{"id":"develop/deno/index-deno","title":"Deno and Redis","description":"With over 80,000 stars and 670+ contributors, Deno is a popular modern runtime for JavaScript and TypeScript. It is built on V8, an open-source JavaScript engine developed by the Chromium Project for Google Chrome and Chromium web browsers.","sidebar":"docs"},"develop/dotnet/aspnetcore/caching/basic/index-basic-caching":{"id":"develop/dotnet/aspnetcore/caching/basic/index-basic-caching","title":"How to add a basic API Cache to your ASP.NET Core application","description":"Redis is synonymous with caching, and for a good reason, Redis is fast and easy to get up and running with and does an excellent job as a cache.","sidebar":"docs"},"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting":{"id":"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting","title":"How to implement a Fixed Window Rate Limiting app using ASP.NET Core & Redis","description":"In this tutorial, we will build an app that implements basic fixed-window rate limiting using Redis & ASP.NET Core.","sidebar":"docs"},"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware":{"id":"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware","title":"Configurable Sliding Window Rate Limiting Middleware for Redis & ASP.NET Core","description":"Let\'s consider the case (which is probably most cases) where we have multiple endpoints we want to rate limit; it doesn\'t make an awful lot of sense to embed rate-limiting in those cases in the logic of the routes themselves. Instead, have something that will intercept requests and check to see if the request is rate-limited before moving onto the appropriate endpoint. To accomplish this, we\'ll build some middleware for just this purpose. And with some light configuration work, we\'ll be able to build some middleware to handle a configurable set of limits.","sidebar":"docs"},"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting":{"id":"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting","title":"How to implement Sliding Window Rate Limiting app using ASP.NET Core & Redis","description":"In this tutorial, we\'ll learn how to build a sliding window rate limiter for ASP.NET Core using Redis.","sidebar":"docs"},"develop/dotnet/index-dotnet":{"id":"develop/dotnet/index-dotnet","title":".NET and Redis","description":"Getting Started"},"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects":{"id":"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects","title":"Add and Retrieve Objects","description":"The Redis OM library supports declarative storage and retrieval of objects from Redis. Without Redis Stack, this is limited to using hashes, and id lookups of objects in Redis. You will still use the Document Attribute to decorate a class you\'d like to store in Redis. From there, all you need to do is either call Insert or InsertAsync on the RedisCollection or Set or SetAsync on the RedisConnection, passing in the object you want to set in Redis. You can then retrieve those objects with Get or GetAsync with the RedisConnection or with FindById or FindByIdAsync in the RedisCollection.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions":{"id":"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions","title":"Apply Functions","description":"Apply functions are functions that you can define as expressions to apply to your data in Redis. In essence, they allow you to combine your data together, and extract the information you want.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/aggregations/groups/groups":{"id":"develop/dotnet/redis-om-dotnet/aggregations/groups/groups","title":"Grouping and Reductions","description":"Grouping and reducing operations using aggregations can be extremely powerful.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/aggregations/intro/intro":{"id":"develop/dotnet/redis-om-dotnet/aggregations/intro/intro","title":"Aggregations Intro","description":"Aggregations are a method of grouping documents together and run processing on them on the server to transform them into data that you need in your application, without having to perform the computation client-side.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index":{"id":"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index","title":"Creating an Index with Redis OM","description":"To unlock some of the nicest functionality of Redis OM, e.g., running searches, matches, aggregations, reductions, mappings, etc... You will need to tell Redis how you want data to be stored and how you want it indexed. One of the features the Redis OM library provides is creating indices that map directly to your objects by declaring the indices as attributes on your class.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters":{"id":"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters","title":"Geo Filters","description":"A really nifty bit of indexing you can do with Redis OM is geo-indexing. To GeoIndex, all you need to do is to mark a GeoLoc field in your model as Indexed and create the index","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries":{"id":"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries","title":"Numeric Queries","description":"In addition to providing capabilities for text queries, Redis OM also provides you the ability to perform numeric equality and numeric range queries. Let us assume a model of:","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries":{"id":"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries","title":"Simple Text Queries","description":"The RedisCollection provides a fluent interface for querying objects stored in redis. This means that if you store an object in Redis with the Redis OM library, and you have Redis Stack running, you can query objects stored in Redis with ease using the LINQ syntax you\'re used to.","sidebar":"docs"},"develop/dotnet/streams/stream-basics":{"id":"develop/dotnet/streams/stream-basics","title":"How to use Redis Streams with .NET","description":"Redis Streams are a powerful data structure that allows you to use Redis as a sort of Message bus to transport messages between different application components. The way streams operate in Redis is very fast and memory efficient. This article will not go over the minutia of every command available for Redis Streams, but rather it\'s aimed to provide a high-level tutorial for how you can use Redis Streams with .NET.","sidebar":"docs"},"develop/guides/netlify/getting-started/index-getting-started":{"id":"develop/guides/netlify/getting-started/index-getting-started","title":"Getting Started with Netlify","description":"{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docs":[{"type":"link","label":"Home","href":"/"},{"type":"link","label":"Getting Started","href":"/howtos/quick-start","docId":"howtos/quick-start/index-quick-start"},{"type":"category","label":"Create","items":[{"type":"link","label":"Overview - All Quick Starts","href":"/create","docId":"create/index-create"},{"type":"link","label":"Redis Functions","href":"/create/redis-functions","docId":"create/redis-functions/index-redis-functions"},{"type":"category","label":"Redis on Azure Cache","items":[{"type":"link","label":"Overview","href":"/create/azure","docId":"create/azure/index-azure"},{"type":"link","label":"Redis on Azure Cache","href":"/create/azure/portal","docId":"create/azure/portal/index-azure-portal"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis on AWS","items":[{"type":"link","label":"Overview","href":"/create/aws","docId":"create/aws/index-aws"},{"type":"link","label":"Redis on AWS","href":"/create/aws/redis-on-aws","docId":"create/aws/redis-on-aws/index-redis-on-aws"},{"type":"link","label":"Building a Slack Bot using AWS S3 and Redis Search and Query Engine","href":"/create/aws/slackbot","docId":"create/aws/slackbot/index-slackbot"},{"type":"link","label":"Deploy and Manage Redis Database on AWS using Terraform","href":"/create/aws/terraform","docId":"create/aws/terraform/index-terraform"},{"type":"link","label":"Building a Real-Time Bidding Platform using NodeJS, AWS Lambda and Redis","href":"/create/aws/bidding-on-aws","docId":"create/aws/bidding-on-aws/index-bidding-on-aws"},{"type":"link","label":"Online Data Migration from AWS Elasticache to Redis","href":"/create/aws/import/database-migration-aws-elasticache-redis-enterprise-cloud/","docId":"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud"},{"type":"link","label":"Building a Real-Time Chat application on AWS using Python and Redis","href":"/create/aws/chatapp","docId":"create/aws/chatapp/index-chatapp"},{"type":"link","label":"Building an Analytics Dashboard using NodeJS, Redis and AWS","href":"/create/aws/analytics-using-aws","docId":"create/aws/analytics-using-aws/index-analytics-using-aws"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis on Docker","items":[{"type":"link","label":"Overview","href":"/create/docker/","docId":"create/docker/index-docker"},{"type":"link","label":"Node.js, Nginx, Redis and Docker","href":"/create/docker/nodejs-nginx-redis","docId":"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis on Kubernetes","items":[{"type":"link","label":"Overview","href":"/create/kubernetes/","docId":"create/kubernetes/index-kubernetes"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Redis on Windows","href":"/create/windows","docId":"create/windows/index-windows"},{"type":"link","label":"Redis using Jenkins","href":"/create/jenkins","docId":"create/jenkins/index-jenkins"},{"type":"category","label":"Redis using Azure Functions","items":[{"type":"link","label":"Getting Started with Azure Functions and Redis","href":"/create/azurefunctions","docId":"create/azurefunctions/index-azurefunctions"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Develop","items":[{"type":"link","label":"Overview","href":"/develop","docId":"develop/index-develop"},{"type":"category","label":"Java","items":[{"type":"link","label":"Overview","href":"/develop/java","docId":"develop/java/index-java"},{"type":"category","label":"Spring","items":[{"type":"link","label":"Overview","href":"/develop/java/spring","docId":"develop/java/spring/index-spring"},{"type":"category","label":"Redis OM Tutorial","items":[{"type":"link","label":"Introduction","href":"/develop/java/spring/redis-om/redis-om-spring","docId":"develop/java/spring/redis-om/redis-om-spring"},{"type":"link","label":"Working with JSON","href":"/develop/java/spring/redis-om/redis-om-spring-json","docId":"develop/java/spring/redis-om/redis-om-spring-json"},{"type":"link","label":"Working with Hashes","href":"/develop/java/spring/redis-om/redis-om-spring-hash","docId":"develop/java/spring/redis-om/redis-om-spring-hash"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis and Spring Course","items":[{"type":"link","label":"Overview","href":"/develop/java/redis-and-spring-course","docId":"develop/java/spring/redis-and-spring-course/index-redis-and-spring-course"},{"type":"link","label":"Up and Running","href":"/develop/java/redis-and-spring-course/lesson_1","docId":"develop/java/spring/redis-and-spring-course/lesson_1/index-lesson_1"},{"type":"link","label":"Spring Data Redis","href":"/develop/java/redis-and-spring-course/lesson_2","docId":"develop/java/spring/redis-and-spring-course/lesson_2/index-lesson_2"},{"type":"link","label":"Mapping & Repositories","href":"/develop/java/redis-and-spring-course/lesson_3","docId":"develop/java/spring/redis-and-spring-course/lesson_3/index-lesson_3"},{"type":"link","label":"User Roles & Secondary Indexes","href":"/develop/java/redis-and-spring-course/lesson_4","docId":"develop/java/spring/redis-and-spring-course/lesson_4/index-lesson_4"},{"type":"link","label":"Books, Categories & The Catalog","href":"/develop/java/redis-and-spring-course/lesson_5","docId":"develop/java/spring/redis-and-spring-course/lesson_5/index-lesson_5"},{"type":"link","label":"Domain Models w/ Redis","href":"/develop/java/redis-and-spring-course/lesson_6","docId":"develop/java/spring/redis-and-spring-course/lesson_6/index-lesson_6"},{"type":"link","label":"Search w/ Redis","href":"/develop/java/redis-and-spring-course/lesson_7","docId":"develop/java/spring/redis-and-spring-course/lesson_7/index-lesson_7"},{"type":"link","label":"Caching w/ Redis","href":"/develop/java/redis-and-spring-course/lesson_9","docId":"develop/java/spring/redis-and-spring-course/lesson_9/index-lesson_9"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Rate Limiting","items":[{"type":"link","label":"Overview","href":"/develop/java/spring/rate-limiting","docId":"develop/java/spring/rate-limiting/index-ratelimiting"},{"type":"category","label":"Fixed Window","items":[{"type":"link","label":"Overview","href":"/develop/java/spring/rate-limiting/fixed-window","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window"},{"type":"link","label":"Reactive Implementation","href":"/develop/java/spring/rate-limiting/fixed-window/reactive","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive"},{"type":"link","label":"Atomicity with Lua","href":"/develop/java/spring/rate-limiting/fixed-window/reactive-lua","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive-lua"},{"type":"link","label":"Atomicity with Gears","href":"/develop/java/spring/rate-limiting/fixed-window/reactive-gears","docId":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive-gears"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"C","href":"/develop/C/","docId":"develop/C/index-c"},{"type":"category","label":"Node.js","items":[{"type":"link","label":"Overview","href":"/develop/node","docId":"develop/node/index-node"},{"type":"link","label":"Getting Started","href":"/develop/node/gettingstarted","docId":"develop/node/gettingstarted/index-gettingstarted"},{"type":"category","label":"Node.js Crash Course","items":[{"type":"link","label":"Overview","href":"/develop/node/node-crash-course","docId":"develop/node/node-crash-course/index-node-crash-course"},{"type":"link","label":"Welcome","href":"/develop/node/nodecrashcourse/welcome","docId":"develop/node/node-crash-course/welcome/index-welcome"},{"type":"link","label":"What is Redis?","href":"/develop/node/nodecrashcourse/whatisredis","docId":"develop/node/node-crash-course/whatisredis/index-whatisredis"},{"type":"link","label":"Redis and Node.js","href":"/develop/node/nodecrashcourse/redisandnodejs","docId":"develop/node/node-crash-course/redisandnodejs/index-redisandnodejs"},{"type":"link","label":"Introducing RedisInsight","href":"/develop/node/nodecrashcourse/introducingredisinsight","docId":"develop/node/node-crash-course/introducingredisinsight/index-introducingredisinsight"},{"type":"link","label":"Sample Application Overview","href":"/develop/node/nodecrashcourse/sampleapplicationoverview","docId":"develop/node/node-crash-course/sampleapplicationoverview/index-sampleapplicationoverview"},{"type":"link","label":"Running the Application","href":"/develop/node/nodecrashcourse/runningtheapplication","docId":"develop/node/node-crash-course/runningtheapplication/index-runningtheapplication"},{"type":"link","label":"Domain Objects with Hashes","href":"/develop/node/nodecrashcourse/domainobjectswithhashes","docId":"develop/node/node-crash-course/domainobjectswithhashes/index-domainobjectswithhashes"},{"type":"link","label":"Redis Extensibility","href":"/develop/node/nodecrashcourse/introductiontomodules","docId":"develop/node/node-crash-course/introductiontomodules/index-introductiontomodules"},{"type":"link","label":"JSON","href":"/develop/node/nodecrashcourse/redisjson","docId":"develop/node/node-crash-course/redisjson/index-redisjson"},{"type":"link","label":"Searching and Querying","href":"/develop/node/nodecrashcourse/redisearch","docId":"develop/node/node-crash-course/redisearch/index-redisearch"},{"type":"link","label":"Checkins with Streams","href":"/develop/node/nodecrashcourse/checkinswithstreams","docId":"develop/node/node-crash-course/checkinswithstreams/index-checkinswithstreams"},{"type":"link","label":"Managing Success","href":"/develop/node/nodecrashcourse/managingsuccess","docId":"develop/node/node-crash-course/managingsuccess/index-managingsuccess"},{"type":"link","label":"Caching","href":"/develop/node/nodecrashcourse/caching","docId":"develop/node/node-crash-course/caching/index-caching"},{"type":"link","label":"Session Storage","href":"/develop/node/nodecrashcourse/sessionstorage","docId":"develop/node/node-crash-course/sessionstorage/index-sessionstorage"},{"type":"link","label":"Advanced Streams","href":"/develop/node/nodecrashcourse/advancedstreams","docId":"develop/node/node-crash-course/advancedstreams/index-advancedstreams"},{"type":"link","label":"Probabilistic Data Structures","href":"/develop/node/nodecrashcourse/redisbloom","docId":"develop/node/node-crash-course/redisbloom/index-redisbloom"},{"type":"link","label":"Wrap Up","href":"/develop/node/nodecrashcourse/coursewrapup","docId":"develop/node/node-crash-course/coursewrapup/index-coursewrapup"}],"collapsed":true,"collapsible":true},{"type":"link","label":"Redis OM for Node.js","href":"/develop/node/redis-om","docId":"develop/node/redis-om/index-redis-om"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Python","items":[{"type":"link","label":"Redis with FastAPI","href":"/develop/python/fastapi","docId":"develop/python/fastapi/index-fastapi"}],"collapsed":true,"collapsible":true},{"type":"category","label":".NET","items":[{"type":"category","label":"ASP.NET Core","items":[{"type":"category","label":"Rate Limiting","items":[{"type":"link","label":"Fixed Window Rate Limiting app using ASP.NET","href":"/develop/dotnet/aspnetcore/rate-limiting/fixed-window","docId":"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting"},{"type":"link","label":"Sliding Window Rate Limiting app using ASP.NET","href":"/develop/dotnet/aspnetcore/rate-limiting/sliding-window","docId":"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting"},{"type":"link","label":"Rate Limiting Middleware","href":"/develop/dotnet/aspnetcore/rate-limiting/middleware","docId":"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Caching","items":[{"type":"link","label":"Basic API Caching using ASP.NET Core","href":"/develop/dotnet/aspnetcore/caching/basic-api-caching","docId":"develop/dotnet/aspnetcore/caching/basic/index-basic-caching"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Redis OM Dotnet","items":[{"type":"link","label":"Add and Retrieve Objects","href":"/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects","docId":"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects"},{"type":"link","label":"Creating an Index","href":"/develop/dotnet/redis-om-dotnet/searching/creating-an-index","docId":"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index"},{"type":"category","label":"Querying","items":[{"type":"link","label":"Simple Text Queries","href":"/develop/dotnet/redis-om-dotnet/simple-text-queries","docId":"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries"},{"type":"link","label":"Numeric Queries","href":"/develop/dotnet/redis-om-dotnet/searching/numeric-queries","docId":"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries"},{"type":"link","label":"Geo Filters","href":"/develop/dotnet/redis-om-dotnet/searching/geo-filters","docId":"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Aggregations","items":[{"type":"link","label":"Aggregations Intro","href":"/develop/dotnet/redis-om-dotnet/aggregations","docId":"develop/dotnet/redis-om-dotnet/aggregations/intro/intro"},{"type":"link","label":"Apply Functions","href":"/develop/dotnet/redis-om-dotnet/aggregations/apply-functions","docId":"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions"},{"type":"link","label":"Grouping and Reductions","href":"/develop/dotnet/redis-om-dotnet/aggregations/groups/groups","docId":"develop/dotnet/redis-om-dotnet/aggregations/groups/groups"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Streams","items":[{"type":"link","label":"Using Redis Streams with .NET","href":"/develop/dotnet/streams/stream-basics","docId":"develop/dotnet/streams/stream-basics"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"Ruby","href":"/develop/ruby/","docId":"develop/ruby/index-ruby"},{"type":"link","label":"PHP","href":"/develop/php/","docId":"develop/php/index-php"},{"type":"link","label":"Deno","href":"/develop/deno/","docId":"develop/deno/index-deno"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Explore","items":[{"type":"link","label":"Overview","href":"/explore","docId":"explore/index-explore"},{"type":"link","label":"Import Data into a Redis database","href":"/explore/import/","docId":"explore/import/index-import"},{"type":"link","label":"Redis Data Source for Grafana","href":"/explore/redisdatasource","docId":"explore/redisdatasource/index-redisdatasource"},{"type":"link","label":"Redis Enterprise Observability with Datadog","href":"/explore/datadog","docId":"explore/datadog/index-datadog"},{"type":"link","label":"RIOT","href":"/explore/riot","docId":"explore/riot/index-riot"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Operate","items":[{"type":"category","label":"Observability","items":[{"type":"link","label":"Redis Data Source for Grafana","href":"/operate/observability/redisdatasource","docId":"operate/observability/redisdatasource/index-redisdatasource"},{"type":"link","label":"Redis Enterprise Observability with Datadog","href":"/operate/observability/datadog","docId":"operate/observability/datadog/index-datadog"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Provisioning","items":[{"type":"link","label":"Deploy and Manage Redis Database on AWS using Terraform","href":"/operate/provisioning/terraform","docId":"operate/provisioning/terraform/index-terraform"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Running Redis at Scale","items":[{"type":"link","label":"Overview","href":"/operate/redis-at-scale","docId":"operate/redis-at-scale/index-redis-at-scale"},{"type":"category","label":"1 Talking to Redis","items":[{"type":"link","label":"1.0 Redis Server Overview","href":"/operate/redis-at-scale/talking-to-redis/redis-server-overview","docId":"operate/redis-at-scale/talking-to-redis/redis-server-overview/index-redis-server-overview"},{"type":"link","label":"1.1 The Command Line Tool: Redis-CLI","href":"/operate/redis-at-scale/talking-to-redis/command-line-tool","docId":"operate/redis-at-scale/talking-to-redis/command-line-tool/index-command-line-tool"},{"type":"link","label":"1.2 Configuring a Redis Server","href":"/operate/redis-at-scale/talking-to-redis/configuring-a-redis-server","docId":"operate/redis-at-scale/talking-to-redis/configuring-a-redis-server/index-configuring-a-redis-server"},{"type":"link","label":"1.3 Redis Clients","href":"/operate/redis-at-scale/talking-to-redis/redis-clients","docId":"operate/redis-at-scale/talking-to-redis/redis-clients/index-redis-clients"},{"type":"link","label":"1.4 Client Performance Improvements","href":"/operate/redis-at-scale/talking-to-redis/client-performance-improvements","docId":"operate/redis-at-scale/talking-to-redis/client-performance-improvements/index-client-performance-improvements"},{"type":"link","label":"1.5 Initial Tuning","href":"/operate/redis-at-scale/talking-to-redis/initial-tuning","docId":"operate/redis-at-scale/talking-to-redis/initial-tuning/index-initial-tuning"}],"collapsed":true,"collapsible":true},{"type":"category","label":"2 Persistence & Durability","items":[{"type":"link","label":"2.0 Introduction to Persistence and Durability\'","href":"/operate/redis-at-scale/persistence-and-durability/introduction","docId":"operate/redis-at-scale/persistence-and-durability/introduction/index-introduction"},{"type":"link","label":"2.1 Persistence options in Redis\'","href":"/operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis","docId":"operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis/index-persistence-options-in-redis"},{"type":"link","label":"2.2 Exercise: Saving a Snapshot","href":"/operate/redis-at-scale/persistence-and-durability/exercise","docId":"operate/redis-at-scale/persistence-and-durability/exercise/index-exercise"}],"collapsed":true,"collapsible":true},{"type":"category","label":"3 High Availability","items":[{"type":"link","label":"3.0 Introduction to High Availability","href":"/operate/redis-at-scale/high-availability/introduction","docId":"operate/redis-at-scale/high-availability/introduction/index-introduction"},{"type":"link","label":"3.1 Basic Replication","href":"/operate/redis-at-scale/high-availability/basic-replication","docId":"operate/redis-at-scale/high-availability/basic-replication/index-basic-replication"},{"type":"link","label":"3.2 Exercise - Enabling Basic Replication","href":"/operate/redis-at-scale/high-availability/exercise-1","docId":"operate/redis-at-scale/high-availability/exercise-1/index-exercise-1"},{"type":"link","label":"3.3 Understanding Sentinels","href":"/operate/redis-at-scale/high-availability/understanding-sentinels","docId":"operate/redis-at-scale/high-availability/understanding-sentinels/index-understanding-sentinels"},{"type":"link","label":"3.4 Exercise - Sentinel Hands-on","href":"/operate/redis-at-scale/high-availability/exercise-2","docId":"operate/redis-at-scale/high-availability/exercise-2/index-exercise-2"}],"collapsed":true,"collapsible":true},{"type":"category","label":"4 Scalability","items":[{"type":"link","label":"4.0 Clustering In Redis","href":"/operate/redis-at-scale/scalability/lustering-in-redis","docId":"operate/redis-at-scale/scalability/clustering-in-redis/index-clustering-in-redis"},{"type":"link","label":"4.1 Exercise - Creating a Redis Cluster","href":"/operate/redis-at-scale/scalability/exercise-1","docId":"operate/redis-at-scale/scalability/exercise-1/index-exercise-1"},{"type":"link","label":"4.2 Using Redis-CLI with a Redis Cluster","href":"/operate/redis-at-scale/scalability/redis-cli-with-redis-cluster","docId":"operate/redis-at-scale/scalability/redis-cli-with-redis-cluster/index-redis-cli-with-redis-cluster"},{"type":"link","label":"4.3 Redis Cluster and Client Libraries","href":"/operate/redis-at-scale/scalability/redis-cluster-and-client-libraries","docId":"operate/redis-at-scale/scalability/redis-cluster-and-client-libraries/index-redis-cluster-and-client-libraries"}],"collapsed":true,"collapsible":true},{"type":"category","label":"5 Observability","items":[{"type":"link","label":"5.0 Introduction to Observability","href":"/operate/redis-at-scale/observability/introduction","docId":"operate/redis-at-scale/observability/introduction/index-introduction"},{"type":"link","label":"5.1 Data points in Redis","href":"/operate/redis-at-scale/observability/data-points-in-redis","docId":"operate/redis-at-scale/observability/data-points-in-redis/index-data-points-in-redis"},{"type":"link","label":"5.2 Getting Redis Statistics","href":"/operate/redis-at-scale/observability/exercise-1","docId":"operate/redis-at-scale/observability/exercise-1/index-exercise-1"},{"type":"link","label":"5.3 Identifying Issues","href":"/operate/redis-at-scale/observability/identifying-issues","docId":"operate/redis-at-scale/observability/identifying-issues/index-identifying-issues"}],"collapsed":true,"collapsible":true},{"type":"category","label":"6 Course wrap-up","items":[{"type":"link","label":"Course Wrap-up","href":"/operate/redis-at-scale/course-wrap-up/","docId":"operate/redis-at-scale/course-wrap-up/index-wrap-up"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"Orchestration","items":[{"type":"link","label":"Overview","href":"/operate/orchestration","docId":"operate/orchestration/index-orchestration"},{"type":"link","label":"Redis on Docker","href":"/operate/orchestration/docker/","docId":"operate/orchestration/docker/index-docker"},{"type":"link","label":"Node.js, Nginx, Redis and Docker","href":"/operate/docker/nodejs-nginx-redis","docId":"operate/orchestration/nodejs-nginx-redis/index-nodejs-nginx-redis"},{"type":"link","label":"Redis on Kubernetes","href":"/operate/orchestration/kubernetes/kubernetes-gke","docId":"operate/orchestration/kubernetes-gke/index-kubernetes-gke"},{"type":"link","label":"Kubernetes Operator: What It Is and Why You Should Really Care About It","href":"/operate/orchestration/kubernetes-operator","docId":"operate/orchestration/kubernetes-operator/index-kubernetes-operator"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"category","label":"HowTos & Tutorials","items":[{"type":"link","label":"Cheat sheet","href":"/howtos/quick-start/cheat-sheet","docId":"howtos/quick-start/cheat-sheets/index-quick-start-cheat-sheet"},{"type":"category","label":"Solutions","items":[{"type":"link","label":"Overview","href":"/howtos/solutions","docId":"howtos/solutions/index-solutions"},{"type":"category","label":"Microservices","items":[{"type":"link","label":"How to Build an E-Commerce App Using Redis with the CQRS Pattern","href":"/howtos/solutions/microservices/cqrs","docId":"howtos/solutions/microservices/cqrs/index-solutions-cqrs"},{"type":"link","label":"Microservices Communication with Redis Streams","href":"/howtos/solutions/microservices/interservice-communication","docId":"howtos/solutions/microservices/interservice-communication/index-solutions-interservice-communication"},{"type":"link","label":"How to use Redis for Query Caching","href":"/howtos/solutions/microservices/caching","docId":"howtos/solutions/microservices/caching/index-solutions-caching"},{"type":"link","label":"How to use Redis for API Gateway Caching","href":"/howtos/solutions/microservices/api-gateway-caching","docId":"howtos/solutions/microservices/api-gateway-caching/index-solutions-api-gateway-caching"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Fraud detection","items":[{"type":"link","label":"Redis for Digital Identity Validation","href":"/howtos/solutions/fraud-detection/digital-identity-validation","docId":"howtos/solutions/fraud-detection/digital-identity-validation/index-digital-identity-validation"},{"type":"link","label":"How to use Redis for Transaction risk scoring","href":"/howtos/solutions/fraud-detection/transaction-risk-scoring","docId":"howtos/solutions/fraud-detection/transaction-risk-scoring/index-transaction-risk-scoring"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Caching architecture","items":[{"type":"link","label":"How to use Redis for Write-behind Caching","href":"/howtos/solutions/caching-architecture/write-behind","docId":"howtos/solutions/caching-architecture/write-behind/index-write-behind"},{"type":"link","label":"How to use Redis for Write through caching strategy","href":"/howtos/solutions/caching-architecture/write-through","docId":"howtos/solutions/caching-architecture/write-through/index-write-through"},{"type":"link","label":"How to use Redis for Cache Prefetching Strategy","href":"/howtos/solutions/caching-architecture/cache-prefetching","docId":"howtos/solutions/caching-architecture/cache-prefetching/index-cache-prefetching"},{"type":"link","label":"How to use Redis for Query Caching","href":"/howtos/solutions/microservices/caching","docId":"howtos/solutions/microservices/caching/index-solutions-caching"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Real-time Inventory","items":[{"type":"link","label":"Available to Promise in Real-time Inventory","href":"/howtos/solutions/real-time-inventory/available-to-promise","docId":"howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise"},{"type":"link","label":"Real-time Local Inventory Search Using Redis","href":"/howtos/solutions/real-time-inventory/local-inventory-search","docId":"howtos/solutions/real-time-inventory/local-inventory-search/index-rti-local-inventory-search"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Mobile Banking","items":[{"type":"link","label":"Mobile Banking Authentication and Session Storage Using Redis","href":"/howtos/solutions/mobile-banking/session-management","docId":"howtos/solutions/mobile-banking/session-management/index-mb-session-management"},{"type":"link","label":"Mobile Banking Account Dashboard Using Redis","href":"/howtos/solutions/mobile-banking/account-dashboard","docId":"howtos/solutions/mobile-banking/account-dashboard/index-mb-account-dashboard"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Vector Database","items":[{"type":"link","label":"How to Perform Vector Similarity Search Using Redis in NodeJS","href":"/howtos/solutions/vector/getting-started-vector","docId":"howtos/solutions/vector/getting-started-vector/index-getting-started-vector"},{"type":"link","label":"How to Build a GenAI Chatbot Using LangChain and Redis","href":"/howtos/solutions/vector/gen-ai-chatbot","docId":"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"How to build a Real-Time Leaderboard app Using Redis","href":"/howtos/leaderboard","docId":"howtos/leaderboard/index-leaderboard"},{"type":"link","label":"How to build a Rate Limiter using Redis","href":"/howtos/ratelimiting","docId":"howtos/ratelimiting/index-ratelimiting"},{"type":"link","label":"How to cache REST API responses Using Redis & NodeJS","href":"/howtos/caching","docId":"howtos/caching/index-caching"},{"type":"category","label":"How to list & search Movies database using Redis Stack","items":[{"type":"link","label":"2. Install Redis Stack","href":"/howtos/moviesdatabase/install","docId":"howtos/moviesdatabase/install/index-install"},{"type":"link","label":"3. Create Index","href":"/howtos/moviesdatabase/create","docId":"howtos/moviesdatabase/create/index-create"},{"type":"link","label":"4. Query Data","href":"/howtos/moviesdatabase/query","docId":"howtos/moviesdatabase/query/index-query"},{"type":"link","label":"5. Manage Index","href":"/howtos/moviesdatabase/manage","docId":"howtos/moviesdatabase/manage/index-manage"},{"type":"link","label":"6. Import datasets","href":"/howtos/moviesdatabase/import","docId":"howtos/moviesdatabase/import/index-import"},{"type":"link","label":"7. Query Movies","href":"/howtos/moviesdatabase/querymovies","docId":"howtos/moviesdatabase/querymovies/index-querymovies"},{"type":"link","label":"8. Aggregation","href":"/howtos/moviesdatabase/aggregation","docId":"howtos/moviesdatabase/aggregation/index-aggregation"},{"type":"link","label":"9. Advanced Option","href":"/howtos/moviesdatabase/advancedoption","docId":"howtos/moviesdatabase/advancedoption/index-advancedoption"},{"type":"link","label":"10. Sample Application","href":"/howtos/moviesdatabase/sampleapp","docId":"howtos/moviesdatabase/sampleapp/index-sampleapp"}],"collapsed":true,"collapsible":true},{"type":"link","label":"How to build a Chat application using Redis","href":"/howtos/chatapp","docId":"howtos/chatapp/index-chatapp"},{"type":"link","label":"How to build a Fraud Detection System using Redis","href":"/howtos/frauddetection","docId":"howtos/frauddetection/index-frauddetection"},{"type":"link","label":"Building a Pipeline for Natural Language Processing using RedisGears","href":"/howtos/nlp","docId":"howtos/nlp/index-nlp"},{"type":"link","label":"Benchmarks for BERT Large Question Answering inference for RedisAI and RedisGears","href":"/howtos/redisai/bert-qa-benchmarking-with-redisai-and-redisgears","docId":"howtos/bert-qa-benchmarking/bert-qa-benchmarking-with-redisai-and-redisgears"},{"type":"link","label":"How to build a HackerNews Clone using Redis","href":"/howtos/hackernews","docId":"howtos/hackernews/index-hackernews"},{"type":"link","label":"Redis Anti-Patterns Every Developer Should Avoid","href":"/howtos/antipatterns/","docId":"howtos/antipatterns/index-antipatterns"},{"type":"link","label":"Building a Social Network Application using Redis Stack","href":"/howtos/socialnetwork/","docId":"howtos/socialnetwork/index-socialnetwork"},{"type":"link","label":"How to Use SSL/TLS With Redis Enterprise","href":"/howtos/security/","docId":"howtos/security/index-tls"},{"type":"link","label":"Building an Analytics dashboard app using Redis","href":"/howtos/analytics","docId":"howtos/analytics/index-analytics"},{"type":"link","label":"Building a Popup Store application using Redis","href":"/howtos/popupstore","docId":"howtos/popupstore/index-popupstore"},{"type":"link","label":"How to build a NodeJS based application on Heroku using Redis","href":"/howtos/herokunodejs","docId":"howtos/herokunodejs/index-herokunodejs"},{"type":"link","label":"How to build a Python based application on Heroku using Redis","href":"/howtos/herokupython","docId":"howtos/herokupython/index-herokupython"},{"type":"link","label":"How to build a Java based application on Heroku using Redis","href":"/howtos/herokujava","docId":"howtos/herokujava/index-herokujava"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Get Involved","items":[{"type":"link","label":"Overview","href":"/community/","docId":"get-involved/index-getinvolved"},{"type":"link","label":"Discord","href":"/community/discord/","docId":"get-involved/discord/index-discord"},{"type":"link","label":"Redis Live","href":"/redis-live/","docId":"get-involved/redis-live/index-redis-live"},{"type":"category","label":"Redis Insiders","items":[{"type":"link","label":"Redis Insiders","href":"/redis-insiders/","docId":"get-involved/redis-insiders/index-redis-insiders"},{"type":"link","label":"Jyotsna Gupta","href":"/redis-insiders/jyotsna-gupta/","docId":"get-involved/redis-insiders/jyotsna-gupta/index-jyotsna-gupta"},{"type":"link","label":"Moiz Kapasi","href":"/redis-insiders/moiz-kapasi/","docId":"get-involved/redis-insiders/moiz-kapasi/index-moiz-kapasi"},{"type":"link","label":"Michael Owolabi","href":"/redis-insiders/michael-owolabi/","docId":"get-involved/redis-insiders/michael-owolabi/index-michael-owolabi"},{"type":"link","label":"Stevan Thomas","href":"/redis-insiders/stevan-thomas/","docId":"get-involved/redis-insiders/stevan-thomas/index-stevan-thomas"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacktoberfest 2021","items":[{"type":"link","label":"Start Here","href":"/hacktoberfest/","docId":"get-involved/hacktoberfest/index-hacktoberfest"},{"type":"link","label":"Lara\'s Hacktoberfest at Redis Story","href":"/hacktoberfest/stories/lara-aasem","docId":"get-involved/hacktoberfest/lara-aasem-story/index-lara-aasem-story"},{"type":"link","label":"Vincent\'s Hacktoberfest at Redis Story","href":"/hacktoberfest/stories/vincent-aceto","docId":"get-involved/hacktoberfest/vincent-aceto-story/index-vincent-aceto-story"}],"collapsed":true,"collapsible":true},{"type":"link","label":"DEVcember","href":"/devcember/","docId":"get-involved/devcember/index-devcember"}],"collapsed":true,"collapsible":true},{"type":"category","label":"E-books","items":[{"type":"link","label":"NoSQL Data Modeling Patterns","href":"/ebooks/8-nosql-data-modeling-patterns","docId":"ebooks/nosql-data-modeling-patterns"},{"type":"link","label":"3 design patterns to speed up MEAN and MERN stack applications","href":"/ebooks/three-caching-design-patterns","docId":"ebooks/three-caching-design-patterns"}],"collapsed":true,"collapsible":true}]},"docs":{"create/aws/analytics-using-aws/index-analytics-using-aws":{"id":"create/aws/analytics-using-aws/index-analytics-using-aws","title":"How to Build and Deploy Your Own Analytics Dashboard using NodeJS and Redis on the AWS Platform","description":"An interactive analytics dashboard serves several purposes. They allow you to share data and provide you with all those vital information to make game-changing decisions at a faster pace. Building a real-time dynamic dashboard using a traditional relational database might require a complex set of queries. By using a NoSQL database like Redis, you can build a powerful interactive and dynamic dashboard with a small number of Redis commands.","sidebar":"docs"},"create/aws/bidding-on-aws/index-bidding-on-aws":{"id":"create/aws/bidding-on-aws/index-bidding-on-aws","title":"How to Build a Real-Time Bidding Platform using NodeJS, AWS Lambda and Redis","description":"Digital technology has propelled us forward to an exciting new era and has transformed almost every aspect of life. We\u2019re more interconnected than ever as communication has become instant. Working from home has now become the norm, helping us pivot to a new way of working during the pandemic. And our ability to reduce carbon emissions by attending work-related events online has meant that we\u2019ve taken greater strides to combat global warming. Continuing this trend is Shamshir Anees and his team, who have created an application that can host digital auctions. By using Redis, data transmission between components was carried out with maximum efficiency, providing users with real-time bidding updates on the dashboard.","sidebar":"docs"},"create/aws/chatapp/index-chatapp":{"id":"create/aws/chatapp/index-chatapp","title":"How to Build a Real Time Chat application on Amazon Web Services using Python and Redis","description":"Real time chat messaging apps are surging in popularity exponentially. Mobile apps like WhatsApp, Facebook, Telegram, Slack, Discord have become \u201ca part and parcel\u201d of our life. Users are addicted to these live chat mobile app conversations as they bring a personal touch and offer a real-time interaction","sidebar":"docs"},"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud":{"id":"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud","title":"How to migrate your database from AWS ElastiCache to Redis without any downtime","description":"Most of the database migration tools available today are offline in nature. They are complex and require manual intervention.","sidebar":"docs"},"create/aws/index-aws":{"id":"create/aws/index-aws","title":"Overview","description":"The following links provide you with the available options to run apps on AWS using Redis:","sidebar":"docs"},"create/aws/README":{"id":"create/aws/README","title":"images","description":""},"create/aws/redis-on-aws/images/README":{"id":"create/aws/redis-on-aws/images/README","title":"images","description":""},"create/aws/redis-on-aws/index-redis-on-aws":{"id":"create/aws/redis-on-aws/index-redis-on-aws","title":"Create Redis database on AWS","description":"Redis Cloud on AWS is fully managed Redis as a service. Designed for modern distributed applications, Redis Cloud on AWS is known for its high performance, infinite scalability and true high availability.","sidebar":"docs"},"create/aws/redis-on-aws/README":{"id":"create/aws/redis-on-aws/README","title":"images","description":""},"create/aws/slackbot/index-slackbot":{"id":"create/aws/slackbot/index-slackbot","title":"How to Build a Slack Bot to Retrieve Lost Files Using AWS S3 and Redis Search and Query Engine","description":"alt_text","sidebar":"docs"},"create/aws/terraform/index-terraform":{"id":"create/aws/terraform/index-terraform","title":"How to Deploy and Manage Redis Database on AWS Using Terraform","description":"terraform","sidebar":"docs"},"create/azure/index-azure":{"id":"create/azure/index-azure","title":"Azure Cache for Redis","description":"The following links provides you with the available options for create instances of Azure Cache for Redis","sidebar":"docs"},"create/azure/portal/index-azure-portal":{"id":"create/azure/portal/index-azure-portal","title":"Create Redis database on Azure Cache","description":"Redis is an open source, in-memory, key-value data store most commonly used as a primary database, cache, message broker, and queue. Redis cache delivers sub-millisecond response times, enabling fast and powerful real-time applications in industries such as gaming, fintech, ad-tech, social media, healthcare, and IoT. Developers love Redis due to its speed, simplicity and performance.","sidebar":"docs"},"create/azurefunctions/index-azurefunctions":{"id":"create/azurefunctions/index-azurefunctions","title":"Getting Started with Azure Functions and Redis","description":"alttext","sidebar":"docs"},"create/cloud/aws/index-aws":{"id":"create/cloud/aws/index-aws","title":"Create Database using AWS Cloud","description":"Redis Cloud on AWS is fully managed Redis as a service. Designed for modern distributed applications, Redis Cloud on AWS is known for its high performance, infinite scalability and true high availability."},"create/cloud/azure/index-azure":{"id":"create/cloud/azure/index-azure","title":"Create Database using Azure Cache for Redis","description":"Azure Cache for Redis is a native fully-managed service on Microsoft Azure. Azure Cache for Redis offers both the Redis open-source (OSS Redis) and a commercial product from Redis (Redis Cloud) as a managed service. It provides secure and dedicated Redis server instances and full Redis API compatibility. The service is operated by Microsoft, hosted on Azure, and accessible to any application within or outside of Azure."},"create/cloud/gcp/index-gcp":{"id":"create/cloud/gcp/index-gcp","title":"Create Database using Google Cloud","description":"Redis Cloud delivers fully managed Redis as a service. It offers all the capabilities of Redis Enterprise while taking care of all the operational aspects associated with operating Redis in the most efficient manner on Google Cloud Platform. Redis Cloud is built on a complete serverless concept, so users don\u2019t need to deal with nodes and clusters"},"create/cloud/images/README":{"id":"create/cloud/images/README","title":"images","description":""},"create/cloud/index-cloud":{"id":"create/cloud/index-cloud","title":"Create Database using Cloud","description":""},"create/cloud/rediscloud/images/README":{"id":"create/cloud/rediscloud/images/README","title":"images","description":""},"create/cloud/rediscloud/index-rediscloud":{"id":"create/cloud/rediscloud/index-rediscloud","title":"Create Database using Redis Cloud","description":"Redis Cloud is a fully managed cloud service by Redis. Built for modern distributed applications, Redis Cloud enables you to run any query, simple or complex, at sub-millisecond performance at virtually infinite scale without worrying about operational complexity or service availability. With modern probabilistic data structures and extensible data models, including Search, JSON, Graph, and Time Series, you can rely on Redis as your data-platform for all your real-time needs."},"create/docker/index-docker":{"id":"create/docker/index-docker","title":"Overview","description":"The following links provide you with the available options to create a new Redis database using Docker","sidebar":"docs"},"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis":{"id":"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis","title":"How to build and run a Node.js application using Nginx, Docker and Redis","description":"Thanks to Node.js - Millions of frontend developers that write JavaScript for the browser are now able to write the server-side code in addition to the client-side code without the need to learn a completely different language. Node.js is a free, open-sourced, cross-platform JavaScript run-time environment. It is capable to handle thousands of concurrent connections with a single server without introducing the burden of managing thread concurrency, which could be a significant source of bugs.","sidebar":"docs"},"create/heroku/index-heroku":{"id":"create/heroku/index-heroku","title":"Overview","description":"The following links provide you with the available options to run apps on Heroku using Redis:"},"create/heroku/portal/index-heroku-portal":{"id":"create/heroku/portal/index-heroku-portal","title":"Create a Redis database on Heroku","description":"Heroku is a cloud Platform as a Service (PaaS) supporting multiple programming languages that is used as a web application deployment model. Heroku lets the developer build, run and scale applications in a similar manner across all the languages(Java, Node.js, Scala, Clojure, Python, PHP, Ruby and Go)."},"create/images/README":{"id":"create/images/README","title":"images","description":""},"create/index-create":{"id":"create/index-create","title":"Create a Redis Database - Quick Starts","description":"The following quick starts shows various ways of how to get started and create a new Redis database:","sidebar":"docs"},"create/jenkins/index-jenkins":{"id":"create/jenkins/index-jenkins","title":"How to Deploy a Redis Enterprise Database from a Jenkins Pipeline","description":"Jenkins is currently the most popular CI(Continuous Integration) tool, with ~15M users. It is an open source automation server which enables developers to reliably build, test, and deploy their software. It was forked in 2011 from a project called Hudson after a dispute with Oracle, and is used for Continuous Integration and Continuous Delivery (CI/CD) and test automation. Jenkins is based on Java and provides over 1700 plugins to automate your developer workflow and save a lot of your time in executing your repetitive tasks.","sidebar":"docs"},"create/kubernetes/index-kubernetes":{"id":"create/kubernetes/index-kubernetes","title":"Overview","description":"The following links provide you with the available options to create a new Redis database on Kubernetes Platforms","sidebar":"docs"},"create/kubernetes/kubernetes-operator/index-kubernetes-operator":{"id":"create/kubernetes/kubernetes-operator/index-kubernetes-operator","title":"Kubernetes Operator: What It Is and Why You Should Really Care About It","description":"My Image"},"create/openshift/index-openshift":{"id":"create/openshift/index-openshift","title":"How to deploy Redis Enterprise on Red Hat OpenShift Container Platform via OperatorHub","description":"Deploying and managing containerized applications is not easy. The rise of microservice architecture has made it cumbersome to deploy containers across multiple environments. Given that containers can be spun up in seconds and at a much higher volume compared to VMs, managing containers across multiple platforms can be extremely challenging."},"create/redis-functions/index-redis-functions":{"id":"create/redis-functions/index-redis-functions","title":"Getting started with Redis Functions","description":"The most impactful addition to Redis version 7.0 is Redis Functions - a new programmability option, improving on scripts by adding modularity, reusability, and better overall developer experience.","sidebar":"docs"},"create/windows/index-windows":{"id":"create/windows/index-windows","title":"How to Install Redis on Windows","description":"You can run Redis on Windows 10 using Windows Subsystem for Linux(a.k.a WSL2). WSL2 is a compatibility layer for running Linux binary executables natively on Windows 10 and Windows Server 2019. WSL2 lets developers run a GNU/Linux environment (that includes command-line tools, utilities, and applications) directly on Windows.","sidebar":"docs"},"develop/C/index-c":{"id":"develop/C/index-c","title":"C and Redis","description":"Find tutorials, examples and technical articles that will help you to develop with Redis and C.","sidebar":"docs"},"develop/deno/index-deno":{"id":"develop/deno/index-deno","title":"Deno and Redis","description":"With over 80,000 stars and 670+ contributors, Deno is a popular modern runtime for JavaScript and TypeScript. It is built on V8, an open-source JavaScript engine developed by the Chromium Project for Google Chrome and Chromium web browsers.","sidebar":"docs"},"develop/dotnet/aspnetcore/caching/basic/index-basic-caching":{"id":"develop/dotnet/aspnetcore/caching/basic/index-basic-caching","title":"How to add a basic API Cache to your ASP.NET Core application","description":"Redis is synonymous with caching, and for a good reason, Redis is fast and easy to get up and running with and does an excellent job as a cache.","sidebar":"docs"},"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting":{"id":"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting","title":"How to implement a Fixed Window Rate Limiting app using ASP.NET Core & Redis","description":"In this tutorial, we will build an app that implements basic fixed-window rate limiting using Redis & ASP.NET Core.","sidebar":"docs"},"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware":{"id":"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware","title":"Configurable Sliding Window Rate Limiting Middleware for Redis & ASP.NET Core","description":"Let\'s consider the case (which is probably most cases) where we have multiple endpoints we want to rate limit; it doesn\'t make an awful lot of sense to embed rate-limiting in those cases in the logic of the routes themselves. Instead, have something that will intercept requests and check to see if the request is rate-limited before moving onto the appropriate endpoint. To accomplish this, we\'ll build some middleware for just this purpose. And with some light configuration work, we\'ll be able to build some middleware to handle a configurable set of limits.","sidebar":"docs"},"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting":{"id":"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting","title":"How to implement Sliding Window Rate Limiting app using ASP.NET Core & Redis","description":"In this tutorial, we\'ll learn how to build a sliding window rate limiter for ASP.NET Core using Redis.","sidebar":"docs"},"develop/dotnet/index-dotnet":{"id":"develop/dotnet/index-dotnet","title":".NET and Redis","description":"Getting Started"},"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects":{"id":"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects","title":"Add and Retrieve Objects","description":"The Redis OM library supports declarative storage and retrieval of objects from Redis. Without Redis Stack, this is limited to using hashes, and id lookups of objects in Redis. You will still use the Document Attribute to decorate a class you\'d like to store in Redis. From there, all you need to do is either call Insert or InsertAsync on the RedisCollection or Set or SetAsync on the RedisConnection, passing in the object you want to set in Redis. You can then retrieve those objects with Get or GetAsync with the RedisConnection or with FindById or FindByIdAsync in the RedisCollection.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions":{"id":"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions","title":"Apply Functions","description":"Apply functions are functions that you can define as expressions to apply to your data in Redis. In essence, they allow you to combine your data together, and extract the information you want.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/aggregations/groups/groups":{"id":"develop/dotnet/redis-om-dotnet/aggregations/groups/groups","title":"Grouping and Reductions","description":"Grouping and reducing operations using aggregations can be extremely powerful.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/aggregations/intro/intro":{"id":"develop/dotnet/redis-om-dotnet/aggregations/intro/intro","title":"Aggregations Intro","description":"Aggregations are a method of grouping documents together and run processing on them on the server to transform them into data that you need in your application, without having to perform the computation client-side.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index":{"id":"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index","title":"Creating an Index with Redis OM","description":"To unlock some of the nicest functionality of Redis OM, e.g., running searches, matches, aggregations, reductions, mappings, etc... You will need to tell Redis how you want data to be stored and how you want it indexed. One of the features the Redis OM library provides is creating indices that map directly to your objects by declaring the indices as attributes on your class.","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters":{"id":"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters","title":"Geo Filters","description":"A really nifty bit of indexing you can do with Redis OM is geo-indexing. To GeoIndex, all you need to do is to mark a GeoLoc field in your model as Indexed and create the index","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries":{"id":"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries","title":"Numeric Queries","description":"In addition to providing capabilities for text queries, Redis OM also provides you the ability to perform numeric equality and numeric range queries. Let us assume a model of:","sidebar":"docs"},"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries":{"id":"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries","title":"Simple Text Queries","description":"The RedisCollection provides a fluent interface for querying objects stored in redis. This means that if you store an object in Redis with the Redis OM library, and you have Redis Stack running, you can query objects stored in Redis with ease using the LINQ syntax you\'re used to.","sidebar":"docs"},"develop/dotnet/streams/stream-basics":{"id":"develop/dotnet/streams/stream-basics","title":"How to use Redis Streams with .NET","description":"Redis Streams are a powerful data structure that allows you to use Redis as a sort of Message bus to transport messages between different application components. The way streams operate in Redis is very fast and memory efficient. This article will not go over the minutia of every command available for Redis Streams, but rather it\'s aimed to provide a high-level tutorial for how you can use Redis Streams with .NET.","sidebar":"docs"},"develop/guides/netlify/getting-started/index-getting-started":{"id":"develop/guides/netlify/getting-started/index-getting-started","title":"Getting Started with Netlify","description":"{n.d(t,{Zo:()=>l,kt:()=>u});var a=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),d=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},l=function(e){var t=d(e.components);return a.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,s=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),m=d(n),u=o,h=m["".concat(c,".").concat(u)]||m[u]||p[u]||s;return n?a.createElement(h,r(r({ref:t},l),{},{components:n})):a.createElement(h,r({ref:t},l))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var s=n.length,r=new Array(s);r[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,r[1]=i;for(var d=2;d{n.d(t,{Z:()=>c});var a=n(67294),o=n(52263);const s="authorByline_VoxI",r="authorLabel_a70t",i="authorProfileImage_URwT";const c=function(e){let{frontMatter:t}=e;const{siteConfig:n}=(0,o.Z)(),c=n.customFields.authors;return a.createElement(a.Fragment,null,t.authors&&a.createElement("div",{className:"docAuthors"},a.createElement("hr",null),t.authors.map((e=>a.createElement("div",{key:e,className:s},a.createElement("img",{className:i,src:`/img/${c[e].image?c[e].image:"default_author_profile_pic.png"}`,alt:`Profile picture for ${c[e].name}`}),a.createElement("div",null,a.createElement("div",{className:r},"Author:"),a.createElement("div",null,a.createElement("a",{href:c[e].link,target:"_blank"},c[e].name),", ",c[e].title))))),a.createElement("hr",null)))}},36773:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(87462),o=(n(67294),n(3905));const s={},r=void 0,i={unversionedId:"howtos/solutions/microservices/common-data/microservices-arch",id:"howtos/solutions/microservices/common-data/microservices-arch",title:"microservices-arch",description:"Lets take a look at the architecture of the demo application:",source:"@site/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",sourceDirName:"howtos/solutions/microservices/common-data",slug:"/howtos/solutions/microservices/common-data/microservices-arch",permalink:"/howtos/solutions/microservices/common-data/microservices-arch",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",tags:[],version:"current",lastUpdatedAt:1702551239,formattedLastUpdatedAt:"Dec 14, 2023",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Lets take a look at the architecture of the demo application:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"products service"),": handles querying products from the database and returning them to the frontend"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"orders service"),": handles validating and creating orders"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"order history service"),": handles querying a customer's order history"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payments service"),": handles processing orders for payment"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"api gateway"),": unifies the services under a single endpoint"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"mongodb/ postgresql"),": serves as the write-optimized database for storing orders, order history, products, etc.")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"You don't need to use MongoDB/ Postgresql as your write-optimized database in the demo application; you can use other ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"prisma supported databases"))," as well. This is just an example.")))}p.isMDXComponent=!0},80990:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(87462),o=(n(67294),n(3905));const s={},r=void 0,i={unversionedId:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",id:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",title:"microservices-ecommerce-ai",description:"The e-commerce microservices application consists of a frontend, built using Next.js with TailwindCSS. The application backend uses Node.js. The data is stored in Redis and either MongoDB or PostgreSQL, using Prisma. Below are screenshots showcasing the frontend of the e-commerce app.",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705608576,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...s}=e;return(0,o.kt)("wrapper",(0,a.Z)({},l,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"The e-commerce microservices application consists of a frontend, built using ",(0,o.kt)("a",{parentName:"p",href:"https://nextjs.org/"},"Next.js")," with ",(0,o.kt)("a",{parentName:"p",href:"https://tailwindcss.com/"},"TailwindCSS"),". The application backend uses ",(0,o.kt)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js"),". The data is stored in ",(0,o.kt)("a",{parentName:"p",href:"https://redis.com/try-free/"},"Redis")," and either MongoDB or PostgreSQL, using ",(0,o.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"Prisma"),". Below are screenshots showcasing the frontend of the e-commerce app."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Dashboard:")," Displays a list of products with different search functionalities, configurable in the settings page.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Products Page",src:n(7050).Z,width:"2618",height:"1194"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Settings:")," Accessible by clicking the gear icon at the top right of the dashboard. Control the search bar, chatbot visibility, and other features here.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Settings Page",src:n(8461).Z,width:"1822",height:"956"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Dashboard (Semantic Text Search):"),' Configured for semantic text search, the search bar enables natural language queries. Example: "pure cotton blue shirts."\n',(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Text Search",src:n(81168).Z,width:"1920",height:"900"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Dashboard (Semantic Image-Based Queries):"),' Configured for semantic image summary search, the search bar allows for image-based queries. Example: "Left chest nike logo."\n',(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Semantic Image Search",src:n(2680).Z,width:"2608",height:"1216"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Chat Bot:")," Located at the bottom right corner of the page, assisting in product searches and detailed views.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Chat Bot",src:n(99609).Z,width:"1920",height:"911"})),(0,o.kt)("p",null,"Selecting a product in the chat displays its details on the dashboard.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Product Details",src:n(73064).Z,width:"2624",height:"1252"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Shopping Cart:"),' Add products to the cart and check out using the "Buy Now" button.\n',(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Shopping Cart",src:n(12224).Z,width:"2624",height:"1244"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Order History:")," Post-purchase, the 'Orders' link in the top navigation bar shows the order status and history.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Order History Page",src:n(14065).Z,width:"2609",height:"674"})),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Admin Panel:")," Accessible via the 'admin' link in the top navigation. Displays purchase statistics and trending products.\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:n(37740).Z,width:"2604",height:"1230"}),"\n",(0,o.kt)("img",{alt:"Redis Microservices E-commerce App Frontend - Admin Page",src:n(96127).Z,width:"2608",height:"858"})))}p.isMDXComponent=!0},10992:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(87462),o=(n(67294),n(3905));const s={},r=void 0,i={unversionedId:"howtos/solutions/vector/common-ai/microservices-source-code-ai",id:"howtos/solutions/vector/common-ai/microservices-source-code-ai",title:"microservices-source-code-ai",description:"Below is a command to the clone the source code for the application used in this tutorial",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",tags:[],version:"current",lastUpdatedAt:1705611366,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("admonition",{title:"GITHUB CODE",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Below is a command to the clone the source code for the application used in this tutorial"),(0,o.kt)("p",{parentName:"admonition"},"git clone --branch v9.2.0 ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"},"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"))))}p.isMDXComponent=!0},35188:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>g,frontMatter:()=>d,metadata:()=>p,toc:()=>u});var a=n(87462),o=(n(67294),n(3905)),s=n(50358),r=n(36773),i=n(80990),c=n(10992);const d={id:"index-solutions-gen-ai-chatbot",title:"How to Build a GenAI Chatbot Using LangChain and Redis",sidebar_label:"How to Build a GenAI Chatbot Using LangChain and Redis",slug:"/howtos/solutions/vector/gen-ai-chatbot",authors:["prasan","will"]},l=void 0,p={unversionedId:"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot",id:"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot",title:"How to Build a GenAI Chatbot Using LangChain and Redis",description:"What you will learn in this tutorial",source:"@site/docs/howtos/solutions/vector/gen-ai-chatbot/index-gen-ai-chatbot.mdx",sourceDirName:"howtos/solutions/vector/gen-ai-chatbot",slug:"/howtos/solutions/vector/gen-ai-chatbot",permalink:"/howtos/solutions/vector/gen-ai-chatbot",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/gen-ai-chatbot/index-gen-ai-chatbot.mdx",tags:[],version:"current",lastUpdatedAt:1705608576,formattedLastUpdatedAt:"Jan 18, 2024",frontMatter:{id:"index-solutions-gen-ai-chatbot",title:"How to Build a GenAI Chatbot Using LangChain and Redis",sidebar_label:"How to Build a GenAI Chatbot Using LangChain and Redis",slug:"/howtos/solutions/vector/gen-ai-chatbot",authors:["prasan","will"]},sidebar:"docs",previous:{title:"How to Perform Vector Similarity Search Using Redis in NodeJS",permalink:"/howtos/solutions/vector/getting-started-vector"},next:{title:"Semantic Text Search Using LangChain (OpenAI) and Redis",permalink:"/howtos/solutions/vector/semantic-text-search"}},m={},u=[{value:"What you will learn in this tutorial",id:"what-you-will-learn-in-this-tutorial",level:2},{value:"Terminology",id:"terminology",level:2},{value:"Microservices architecture for an e-commerce application",id:"microservices-architecture-for-an-e-commerce-application",level:2},{value:"E-commerce application frontend using Next.js and Tailwind",id:"e-commerce-application-frontend-using-nextjs-and-tailwind",level:2},{value:"Chatbot architecture",id:"chatbot-architecture",level:2},{value:"Flow diagram",id:"flow-diagram",level:3},{value:"Sample user prompt and AI response",id:"sample-user-prompt-and-ai-response",level:3},{value:"Database setup",id:"database-setup",level:2},{value:"Sample data",id:"sample-data",level:3},{value:"OpenAI embeddings seeding",id:"openai-embeddings-seeding",level:3},{value:"Setting up the chatbot API",id:"setting-up-the-chatbot-api",level:2},{value:"API end point",id:"api-end-point",level:3},{value:"API implementation",id:"api-implementation",level:3},{value:"Ready to use Redis for genAI chatbot?",id:"ready-to-use-redis-for-genai-chatbot",level:2},{value:"Further reading",id:"further-reading",level:2}],h={toc:u};function g(e){let{components:t,...l}=e;return(0,o.kt)("wrapper",(0,a.Z)({},h,l,{components:t,mdxType:"MDXLayout"}),(0,o.kt)(s.Z,{frontMatter:d,mdxType:"Authors"}),(0,o.kt)("h2",{id:"what-you-will-learn-in-this-tutorial"},"What you will learn in this tutorial"),(0,o.kt)("p",null,"In this tutorial, you'll learn how to build a GenAI chatbot using ",(0,o.kt)("inlineCode",{parentName:"p"},"LangChain")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Redis"),". You'll also learn how to use ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model to generate responses to user queries and how to use Redis to store and retrieve data."),(0,o.kt)("p",null,"Here's what's covered:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"E-Commerce App")," : A sample e-commerce application where users can search for products and ask questions about them, add them to their cart, and purchase them."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Chatbot Architecture")," : The architecture of the chatbot, including the flow diagram, sample user prompt and it's AI response."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Database setup")," : Generating OpenAI embeddings for products and storing them in Redis."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Setting up the chatbot API")," : Creating a chatbot API that uses OpenAI and Redis to answer user questions and recommend products.")),(0,o.kt)("h2",{id:"terminology"},"Terminology"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Generative AI"),", also known as ",(0,o.kt)("strong",{parentName:"p"},"GenAI"),", is a category of artificial intelligence that specializes in creating new content based on pre-existing data. It can generate a wide array of content types, including text, images, videos, sounds, code, 3D designs, and other media formats. Unlike traditional AI models that focus on analyzing and interpreting existing data, GenAI models learn from existing data and then use their knowledge to generate something entirely new."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("a",{parentName:"strong",href:"https://js.langchain.com"},"LangChain"))," is an innovative library for building language model applications. It offers a structured way to combine different components like language models (e.g., OpenAI's models), storage solutions (like Redis), and custom logic. This modular approach facilitates the creation of sophisticated AI applications, including chatbots."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("a",{parentName:"strong",href:"https://openai.com/"},"OpenAI"))," provides advanced language models like GPT-3, which have revolutionized the field with their ability to understand and generate human-like text. These models form the backbone of many modern AI applications, including chatbots."),(0,o.kt)("h2",{id:"microservices-architecture-for-an-e-commerce-application"},"Microservices architecture for an e-commerce application"),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)(r.default,{mdxType:"InitialMicroservicesArchitecture"}),(0,o.kt)("h2",{id:"e-commerce-application-frontend-using-nextjs-and-tailwind"},"E-commerce application frontend using Next.js and Tailwind"),(0,o.kt)(i.default,{mdxType:"MicroservicesEcommerceAIDesign"}),(0,o.kt)("h2",{id:"chatbot-architecture"},"Chatbot architecture"),(0,o.kt)("h3",{id:"flow-diagram"},"Flow diagram"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"flow diagram",src:n(5402).Z,width:"1801",height:"943"})),(0,o.kt)("p",null,"1> ",(0,o.kt)("strong",{parentName:"p"},"Create Standalone Question"),": Create a standalone question using ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model."),(0,o.kt)("p",null,"A standalone question is just a question reduced to the minimum number of words needed to express the request for information."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"//Example\nuserQuestion =\n \"I'm thinking of buying one of your T-shirts but I need to know what your returns policy is as some T-shirts just don't fit me and I don't want to waste money.\";\n\n//semanticMeaning of above question\nstandAloneQuestion = 'What is your return policy?';\n")),(0,o.kt)("p",null,"2> ",(0,o.kt)("strong",{parentName:"p"},"Create Embeddings for Question"),": Once the question is created, ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model generates an embedding for the question."),(0,o.kt)("p",null,"3> ",(0,o.kt)("strong",{parentName:"p"},"Find Nearest Match in Redis Vector Store"),": The embedding is then used to query ",(0,o.kt)("inlineCode",{parentName:"p"},"Redis")," vector store. The system searches for the nearest match to the question embedding among stored vectors"),(0,o.kt)("p",null,"4> ",(0,o.kt)("strong",{parentName:"p"},"Get Answer"),": With the user initial question, the nearest match from the vector store, and the conversation memory, ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model generates an answer. This answer is then provided to the user."),(0,o.kt)("p",null,"Note : The system maintains a conversation memory, which tracks the ongoing conversation's context. This memory is crucial for ensuring the continuity and relevance of the conversation."),(0,o.kt)("p",null,"5> ",(0,o.kt)("strong",{parentName:"p"},"User Receives Answer"),": The answer is sent back to the user, completing the interaction cycle. The conversation memory is updated with this latest exchange to inform future responses."),(0,o.kt)("h3",{id:"sample-user-prompt-and-ai-response"},"Sample user prompt and AI response"),(0,o.kt)("p",null,"Say, OriginalQuestion of user is as follows:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"I am looking for a watch, Can you recommend anything for formal occasions with price under 50 dollars?")),(0,o.kt)("p",null,"Converted standaloneQuestion by openAI is as follows:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"What watches do you recommend for formal occasions with a price under $50?")),(0,o.kt)("p",null,"After vector similarity search on ",(0,o.kt)("strong",{parentName:"p"},"Redis"),", we get the following similarProducts:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},"similarProducts = [\n {\n pageContent: ` Product details are as follows:\n productId: 11005.\n productDisplayName: Puma Men Visor 3HD Black Watch.\n price: 5495 ...`,\n metadata: { productId: '11005' },\n },\n {\n pageContent: ` Product details are as follows:\n productId: 11006.\n productDisplayName: Puma Men Race Luminous Black Chronograph Watch.\n price: 7795 ... `,\n metadata: { productId: '11006' },\n },\n];\n")),(0,o.kt)("p",null,"The final openAI response with above context and earlier chat history (if any) is as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},'answer = `I recommend two watches for formal occasions with a price under $50. \n\nFirst, we have the Puma Men Visor 3HD Black Watch priced at $54.95. This watch features a heavy-duty design with a stylish dial and chunky casing, giving it a tough appearance - perfect for navigating the urban jungle. It has a square dial shape and a 32 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters. \n\nSecond, we have the Puma Men Race Luminous Black Chronograph Watch priced at $77.95. This watch also features a heavy-duty design with a stylish dial and chunky casing. It has a round dial shape and a 40 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters. \n\nBoth these watches from Puma are perfect for formal occasions and are priced under $50. I hope this helps, and please let me know if you have any other questions!`;\n')),(0,o.kt)("h2",{id:"database-setup"},"Database setup"),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Sign up for an ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://platform.openai.com/"},"OpenAI account"))," to get your API key to be used in the demo (add OPEN_AI_API_KEY variable in .env file). You can also refer to the ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://platform.openai.com/docs/api-reference/introduction"},"OpenAI API documentation"))," for more information.")),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)("h3",{id:"sample-data"},"Sample data"),(0,o.kt)("p",null,"For the purposes of this tutorial, let's consider a simplified e-commerce context. The ",(0,o.kt)("inlineCode",{parentName:"p"},"products")," JSON provided offers a glimpse into AI search functionalities we'll be operating on."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/fashion-dataset/001/products/*.json"',title:'"database/fashion-dataset/001/products/*.json"'},"const products = [\n {\n productId: '11000',\n price: 3995,\n productDisplayName: 'Puma Men Slick 3HD Yellow Black Watches',\n variantName: 'Slick 3HD Yellow',\n brandName: 'Puma',\n ageGroup: 'Adults-Men',\n gender: 'Men',\n displayCategories: 'Accessories',\n masterCategory_typeName: 'Accessories',\n subCategory_typeName: 'Watches',\n styleImages_default_imageURL:\n 'http://host.docker.internal:8080/images/11000.jpg',\n productDescriptors_description_value:\n '

Stylish and comfortable, ...',\n stockQty: 25,\n },\n //...\n];\n")),(0,o.kt)("h3",{id:"openai-embeddings-seeding"},"OpenAI embeddings seeding"),(0,o.kt)("p",null,"Below is the sample code to seed ",(0,o.kt)("inlineCode",{parentName:"p"},"products")," data as openAI embeddings into Redis."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/src/open-ai.ts"',title:'"database/src/open-ai.ts"'},"import { Document } from 'langchain/document';\nimport { OpenAIEmbeddings } from 'langchain/embeddings/openai';\nimport { RedisVectorStore } from 'langchain/vectorstores/redis';\n\n/**\n * Adds OpenAI embeddings to Redis for the given products.\n *\n * @param _products - An array of (ecommerce) products.\n * @param _redisClient - The Redis client used to connect to the Redis server.\n * @param _openAIApiKey - The API key for accessing the OpenAI service.\n */\nconst addOpenAIEmbeddingsToRedis = async (\n _products,\n _redisClient,\n _openAIApiKey,\n) => {\n if (_products?.length > 0 && _redisClient && _openAIApiKey) {\n // Check if the data is already seeded\n const existingKeys = await _redisClient.keys('openAIProducts:*');\n if (existingKeys.length > 0) {\n console.log('seeding openAIEmbeddings skipped !');\n return;\n }\n\n const vectorDocs: Document[] = [];\n // Create a document for each product\n for (let product of _products) {\n let doc = new Document({\n metadata: {\n productId: product.productId,\n },\n pageContent: ` Product details are as follows:\n productId: ${product.productId}.\n \n productDisplayName: ${product.productDisplayName}.\n \n price: ${product.price}.\n \n variantName: ${product.variantName}.\n \n brandName: ${product.brandName}.\n \n ageGroup: ${product.ageGroup}.\n \n gender: ${product.gender}.\n \n productColors: ${product.productColors}\n \n Category: ${product.displayCategories}, ${product.masterCategory_typeName} - ${product.subCategory_typeName}\n \n productDescription: ${product.productDescriptors_description_value}`,\n });\n\n vectorDocs.push(doc);\n }\n\n // Create a new OpenAIEmbeddings instance\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: _openAIApiKey,\n });\n // Add the documents to the RedisVectorStore\n const vectorStore = await RedisVectorStore.fromDocuments(\n vectorDocs,\n embeddings,\n {\n redisClient: _redisClient,\n indexName: 'openAIProductsIdx',\n keyPrefix: 'openAIProducts:',\n },\n );\n console.log('seeding OpenAIEmbeddings completed');\n }\n};\n")),(0,o.kt)("p",null,"You can observe openAIProducts JSON in RedisInsight:"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight AI products",src:n(17984).Z,width:"1920",height:"1054"})),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Download ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://redis.com/redis-enterprise/redis-insight/"},"RedisInsight"))," to visually explore your Redis data or to engage with raw Redis commands in the workbench.")),(0,o.kt)("h2",{id:"setting-up-the-chatbot-api"},"Setting up the chatbot API"),(0,o.kt)("p",null,"Once products data is seeded as openAI embeddings into Redis, we can create a ",(0,o.kt)("inlineCode",{parentName:"p"},"chatbot")," API to answer user questions and recommend products."),(0,o.kt)("h3",{id:"api-end-point"},"API end point"),(0,o.kt)("p",null,"The code that follows shows an example API request and response for the ",(0,o.kt)("inlineCode",{parentName:"p"},"chatBot")," API:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'POST http://localhost:3000/products/chatBot\n{\n "userMessage":"I am looking for a watch, Can you recommend anything for formal occasions with price under 50 dollars?"\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Response")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "data": "I recommend two watches for formal occasions with a price under $50.\n\n First, we have the Puma Men Visor 3HD Black Watch priced at $54.95. This watch features a heavy-duty design with a stylish dial and chunky casing, giving it a tough appearance - perfect for navigating the urban jungle. It has a square dial shape and a 32 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters.\n\n Second, we have the Puma Men Race Luminous Black Chronograph Watch priced at $77.95. This watch also features a heavy-duty design with a stylish dial and chunky casing. It has a round dial shape and a 40 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters.\n\n Both these watches from Puma are perfect for formal occasions and are priced under $50. I hope this helps, and please let me know if you have any other questions!",\n\n "error": null,\n "auth": "SES_54f211db-50a7-45df-8067-c3dc4272beb2"\n}\n')),(0,o.kt)("h3",{id:"api-implementation"},"API implementation"),(0,o.kt)("p",null,"When you make a request, it goes through the API gateway to the ",(0,o.kt)("inlineCode",{parentName:"p"},"products")," service. Ultimately, it ends up calling an ",(0,o.kt)("inlineCode",{parentName:"p"},"chatBotMessage")," function which looks as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"import {\n ChatOpenAI,\n ChatOpenAICallOptions,\n} from 'langchain/chat_models/openai';\nimport { PromptTemplate } from 'langchain/prompts';\nimport { OpenAIEmbeddings } from 'langchain/embeddings/openai';\nimport { RedisVectorStore } from 'langchain/vectorstores/redis';\nimport { StringOutputParser } from 'langchain/schema/output_parser';\nimport { Document } from 'langchain/document';\n\nlet llm: ChatOpenAI;\n\nconst chatBotMessage = async (\n _userMessage: string,\n _sessionId: string,\n _openAIApiKey: string,\n) => {\n const CHAT_BOT_LOG = 'CHAT_BOT_LOG_STREAM';\n const redisWrapperInst = getRedis();\n\n // Add user message to chat history\n const chatHistoryName = 'chatHistory:' + _sessionId;\n redisWrapperInst.addItemToList(\n chatHistoryName,\n 'userMessage: ' + _userMessage,\n );\n // add log\n addMessageToStream(\n { name: 'originalQuestion', comments: _userMessage },\n CHAT_BOT_LOG,\n );\n\n // (1) Create a standalone question\n const standaloneQuestion = await convertToStandAloneQuestion(\n _userMessage,\n _sessionId,\n _openAIApiKey,\n );\n // add log\n addMessageToStream(\n { name: 'standaloneQuestion', comments: standaloneQuestion },\n CHAT_BOT_LOG,\n );\n\n // (2) Get similar products from Redis\n const similarProducts = await getSimilarProductsByVSS(\n standaloneQuestion,\n _openAIApiKey,\n );\n if (similarProducts?.length) {\n // add log\n addMessageToStream(\n { name: 'similarProducts', comments: JSON.stringify(similarProducts) },\n CHAT_BOT_LOG,\n );\n }\n\n // Combine the product details into a single document\n const productDetails = combineVectorDocuments(similarProducts);\n console.log('productDetails:', productDetails);\n\n // (3) Get answer from OpenAI\n const answer = await convertToAnswer(\n _userMessage,\n standaloneQuestion,\n productDetails,\n _sessionId,\n _openAIApiKey,\n );\n // add log\n addMessageToStream({ name: 'answer', comments: answer }, CHAT_BOT_LOG);\n\n // Add answer to chat history\n redisWrapperInst.addItemToList(\n chatHistoryName,\n 'openAIMessage(You): ' + answer,\n );\n\n return answer;\n};\n")),(0,o.kt)("p",null,"Below function converts the userMessage to standaloneQuestion using ",(0,o.kt)("inlineCode",{parentName:"p"},"openAI")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"// (1) Create a standalone question\nconst convertToStandAloneQuestion = async (\n _userQuestion: string,\n _sessionId: string,\n _openAIApiKey: string,\n) => {\n const llm = getOpenAIInstance(_openAIApiKey);\n\n const chatHistory = await getChatHistory(_sessionId);\n\n const standaloneQuestionTemplate = `Given some conversation history (if any) and a question, convert it to a standalone question. \n ***********************************************************\n conversation history: \n ${chatHistory}\n ***********************************************************\n question: {question} \n standalone question:`;\n\n const standaloneQuestionPrompt = PromptTemplate.fromTemplate(\n standaloneQuestionTemplate,\n );\n\n const chain = standaloneQuestionPrompt\n .pipe(llm)\n .pipe(new StringOutputParser());\n\n const response = await chain.invoke({\n question: _userQuestion,\n });\n\n return response;\n};\nconst getOpenAIInstance = (_openAIApiKey: string) => {\n if (!llm) {\n llm = new ChatOpenAI({\n openAIApiKey: _openAIApiKey,\n });\n }\n return llm;\n};\n\nconst getChatHistory = async (_sessionId: string, _separator?: string) => {\n let chatHistory = '';\n if (!_separator) {\n _separator = '\\n\\n';\n }\n if (_sessionId) {\n const redisWrapperInst = getRedis();\n const chatHistoryName = 'chatHistory:' + _sessionId;\n const items = await redisWrapperInst.getAllItemsFromList(chatHistoryName);\n\n if (items?.length) {\n chatHistory = items.join(_separator);\n }\n }\n return chatHistory;\n};\nconst combineVectorDocuments = (\n _vectorDocs: Document[],\n _separator?: string,\n) => {\n if (!_separator) {\n _separator = '\\n\\n --------------------- \\n\\n';\n }\n return _vectorDocs.map((doc) => doc.pageContent).join(_separator);\n};\n")),(0,o.kt)("p",null,"Below function uses ",(0,o.kt)("inlineCode",{parentName:"p"},"Redis")," to find similar products for the standaloneQuestion"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"// (2) Get similar products from Redis\nconst getSimilarProductsByVSS = async (\n _standAloneQuestion: string,\n _openAIApiKey: string,\n) => {\n const client = getNodeRedisClient();\n\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: _openAIApiKey,\n });\n const vectorStore = new RedisVectorStore(embeddings, {\n redisClient: client,\n indexName: 'openAIProductsIdx',\n keyPrefix: 'openAIProducts:',\n });\n\n const KNN = 3;\n /* Simple standalone search in the vector DB */\n const vectorDocs = await vectorStore.similaritySearch(\n _standAloneQuestion,\n KNN,\n );\n\n return vectorDocs;\n};\n")),(0,o.kt)("p",null,"Below function uses ",(0,o.kt)("inlineCode",{parentName:"p"},"openAI")," to convert the standaloneQuestion, similar products from Redis and other context to a human understandable answer."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"// (3) Get answer from OpenAI\nconst convertToAnswer = async (\n _originalQuestion: string,\n _standAloneQuestion: string,\n _productDetails: string,\n _sessionId: string,\n _openAIApiKey: string,\n) => {\n const llm = getOpenAIInstance(_openAIApiKey);\n\n const chatHistory = await getChatHistory(_sessionId);\n\n const answerTemplate = `\n Please assume the persona of a retail shopping assistant for this conversation.\n Use a friendly tone, and assume the target audience are normal people looking for a product in a ecommerce website.\n\n ***********************************************************\n ${\n chatHistory\n ? `\n Conversation history between user and you is : \n ${chatHistory}\n `\n : ''\n }\n ***********************************************************\n OriginalQuestion of user is : {originalQuestion}\n ***********************************************************\n converted stand alone question is : {standAloneQuestion}\n ***********************************************************\n resulting details of products for the stand alone question are :\n {productDetails}\n Note : Different product details are separated by \"---------------------\" (if any) \n ***********************************************************\n Answer the question based on the context provided and the conversation history.\n \n If you don't know the answer, please direct the questioner to email help@redis.com. Don't try to suggest any product out of context as it may not be in the store.\n\n Let the answer include product display name, price and optional other details based on question asked.\n\n Let the product display name be a link like productDisplayName \n so that user can click on it and go to the product page with help of productId.\n \n answer: `;\n\n const answerPrompt = PromptTemplate.fromTemplate(answerTemplate);\n const chain = answerPrompt.pipe(llm).pipe(new StringOutputParser());\n\n const response = await chain.invoke({\n originalQuestion: _originalQuestion,\n standAloneQuestion: _standAloneQuestion,\n productDetails: _productDetails,\n });\n\n return response;\n};\n")),(0,o.kt)("p",null,"You can observe chat history and intermediate chat logs in RedisInsight:"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight chat history",src:n(42614).Z,width:"1920",height:"1056"})),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight chat log",src:n(77193).Z,width:"1920",height:"1052"})),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Download ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://redis.com/redis-enterprise/redis-insight/"},"RedisInsight"))," to visually explore your Redis data or to engage with raw Redis commands in the workbench.")),(0,o.kt)("h2",{id:"ready-to-use-redis-for-genai-chatbot"},"Ready to use Redis for genAI chatbot?"),(0,o.kt)("p",null,"Building a GenAI chatbot using LangChain and Redis involves integrating advanced AI models with efficient storage solutions. This tutorial covers the fundamental steps and code needed to develop a chatbot capable of handling e-commerce queries. With these tools, you can create a responsive, intelligent chatbot for a variety of applications"),(0,o.kt)("h2",{id:"further-reading"},"Further reading"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"/howtos/solutions/vector/getting-started-vector"},"Perform vector similarity search using Redis"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/get_started/quickstart"},"LangChain JS")),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://scrimba.com/learn/langchain"},"Learn LangChain")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/integrations/vectorstores/redis"},"LangChain redis integration")))))}g.isMDXComponent=!0},2680:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-semantic-image-770befcd5c2129a025fc5fe9058d286f.png"},81168:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-semantic-text-e92f1bb2c539726c3125969a90d5a5d0.png"},7050:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-41b6a52ee5d36a9db8b513d285f1d826.png"},99609:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/02-ai-bot-d5546b6243f616636d6f1b5de453d167.png"},73064:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/03-ai-bot-product-ed8e13e4a32f72b952d683473a4c4d0f.png"},12224:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/04-ai-product-shopping-cart-5445685389780e76ba7135e47f0ad20b.png"},14065:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/05-order-history-fa1ebafcf8ac4ee027f5616a00044ee9.png"},37740:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/06-admin-charts-5ae00e6182be0b4ada06049f5d18d0aa.png"},96127:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/07-admin-top-trending-941390270b22d7b4243b386af50ec743.png"},8461:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/08-settings-ai-3e13b6cf77c050ec54d6b444f47624bc.png"},5402:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/chat-bot-flow-c7e389bbe40a85354630e0ec8b45243e.png"},17984:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-ai-products-43d2d9e8851e513777b5390c8c385c26.png"},42614:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-chat-history-64378d953fada2307e36455db66ec5d6.png"},77193:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-chat-log-ab79e77e0998eadc2bb5b124911105ce.png"}}]); \ No newline at end of file diff --git a/assets/js/dc77741e.ec95862b.js b/assets/js/dc77741e.ec95862b.js deleted file mode 100644 index f3f6debfe8..0000000000 --- a/assets/js/dc77741e.ec95862b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[1234,4074,3482,7310],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>u});var a=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),d=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},l=function(e){var t=d(e.components);return a.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,s=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),m=d(n),u=o,h=m["".concat(c,".").concat(u)]||m[u]||p[u]||s;return n?a.createElement(h,r(r({ref:t},l),{},{components:n})):a.createElement(h,r({ref:t},l))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var s=n.length,r=new Array(s);r[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,r[1]=i;for(var d=2;d{n.d(t,{Z:()=>c});var a=n(67294),o=n(52263);const s="authorByline_VoxI",r="authorLabel_a70t",i="authorProfileImage_URwT";const c=function(e){let{frontMatter:t}=e;const{siteConfig:n}=(0,o.Z)(),c=n.customFields.authors;return a.createElement(a.Fragment,null,t.authors&&a.createElement("div",{className:"docAuthors"},a.createElement("hr",null),t.authors.map((e=>a.createElement("div",{key:e,className:s},a.createElement("img",{className:i,src:`/img/${c[e].image?c[e].image:"default_author_profile_pic.png"}`,alt:`Profile picture for ${c[e].name}`}),a.createElement("div",null,a.createElement("div",{className:r},"Author:"),a.createElement("div",null,a.createElement("a",{href:c[e].link,target:"_blank"},c[e].name),", ",c[e].title))))),a.createElement("hr",null)))}},36773:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(87462),o=(n(67294),n(3905));const s={},r=void 0,i={unversionedId:"howtos/solutions/microservices/common-data/microservices-arch",id:"howtos/solutions/microservices/common-data/microservices-arch",title:"microservices-arch",description:"Lets take a look at the architecture of the demo application:",source:"@site/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",sourceDirName:"howtos/solutions/microservices/common-data",slug:"/howtos/solutions/microservices/common-data/microservices-arch",permalink:"/howtos/solutions/microservices/common-data/microservices-arch",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",tags:[],version:"current",lastUpdatedAt:1702551239,formattedLastUpdatedAt:"Dec 14, 2023",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Lets take a look at the architecture of the demo application:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"products service"),": handles querying products from the database and returning them to the frontend"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"orders service"),": handles validating and creating orders"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"order history service"),": handles querying a customer's order history"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payments service"),": handles processing orders for payment"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"api gateway"),": unifies the services under a single endpoint"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"mongodb/ postgresql"),": serves as the write-optimized database for storing orders, order history, products, etc.")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"You don't need to use MongoDB/ Postgresql as your write-optimized database in the demo application; you can use other ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"prisma supported databases"))," as well. This is just an example.")))}p.isMDXComponent=!0},80990:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(87462),o=(n(67294),n(3905));const s={},r=void 0,i={unversionedId:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",id:"howtos/solutions/vector/common-ai/microservices-ecommerce-ai",title:"microservices-ecommerce-ai",description:"The e-commerce microservices application consists of a frontend, built using Next.js with TailwindCSS. The application backend uses Node.js. The data is stored in",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",tags:[],version:"current",lastUpdatedAt:1702551239,formattedLastUpdatedAt:"Dec 14, 2023",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...s}=e;return(0,o.kt)("wrapper",(0,a.Z)({},l,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"The e-commerce microservices application consists of a frontend, built using ",(0,o.kt)("a",{parentName:"p",href:"https://nextjs.org/"},"Next.js")," with ",(0,o.kt)("a",{parentName:"p",href:"https://tailwindcss.com/"},"TailwindCSS"),". The application backend uses ",(0,o.kt)("a",{parentName:"p",href:"https://nodejs.org"},"Node.js"),". The data is stored in\n",(0,o.kt)("a",{parentName:"p",href:"https://redis.com/try-free/"},"Redis")," and MongoDB/ Postgressql using ",(0,o.kt)("a",{parentName:"p",href:"https://www.prisma.io/docs/reference/database-reference/supported-databases"},"Prisma"),". Below you will find screenshots of the frontend of the e-commerce app:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"Dashboard"),": Shows the list of products with search functionality"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend products page",src:n(7050).Z,width:"1024",height:"487"}))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"Chat bot"),": The chat bot is available on the bottom right corner of the page. It can be used to search for products and view the product details."),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend chat bot",src:n(99609).Z,width:"2618",height:"1242"})),(0,o.kt)("p",{parentName:"li"},"Clicking on a product in the chat shows the product details on dashboard"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend product details",src:n(73064).Z,width:"2624",height:"1252"}))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"Shopping Cart"),': Add products to the cart, then check out using the "Buy Now" button\n',(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend shopping cart",src:n(15030).Z,width:"2624",height:"1244"}))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"Order history"),": Once an order is placed, the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orders")," link in the top navigation bar shows the order status and history"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend order history page",src:n(14065).Z,width:"2609",height:"674"}))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"Admin"),": The ",(0,o.kt)("inlineCode",{parentName:"p"},"admin")," link in the top navigation bar shows purchase stats and trending products."),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend admin page",src:n(37740).Z,width:"2604",height:"1230"}),"\n",(0,o.kt)("img",{alt:"redis microservices e-commerce app frontend admin page",src:n(96127).Z,width:"2608",height:"858"})))))}p.isMDXComponent=!0},10992:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var a=n(87462),o=(n(67294),n(3905));const s={},r=void 0,i={unversionedId:"howtos/solutions/vector/common-ai/microservices-source-code-ai",id:"howtos/solutions/vector/common-ai/microservices-source-code-ai",title:"microservices-source-code-ai",description:"Below is a command to the clone the source code for the application used in this tutorial",source:"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",sourceDirName:"howtos/solutions/vector/common-ai",slug:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",permalink:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",tags:[],version:"current",lastUpdatedAt:1702667455,formattedLastUpdatedAt:"Dec 15, 2023",frontMatter:{}},c={},d=[],l={toc:d};function p(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("admonition",{title:"GITHUB CODE",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Below is a command to the clone the source code for the application used in this tutorial"),(0,o.kt)("p",{parentName:"admonition"},"git clone --branch v7.1.0 ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"},"https://github.com/redis-developer/redis-microservices-ecommerce-solutions"))))}p.isMDXComponent=!0},35188:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>g,frontMatter:()=>d,metadata:()=>p,toc:()=>u});var a=n(87462),o=(n(67294),n(3905)),s=n(50358),r=n(36773),i=n(80990),c=n(10992);const d={id:"index-solutions-gen-ai-chatbot",title:"How to Build a GenAI Chatbot Using LangChain and Redis",sidebar_label:"How to Build a GenAI Chatbot Using LangChain and Redis",slug:"/howtos/solutions/vector/gen-ai-chatbot",authors:["prasan","will"]},l=void 0,p={unversionedId:"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot",id:"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot",title:"How to Build a GenAI Chatbot Using LangChain and Redis",description:"What you will learn in this tutorial",source:"@site/docs/howtos/solutions/vector/gen-ai-chatbot/index-gen-ai-chatbot.mdx",sourceDirName:"howtos/solutions/vector/gen-ai-chatbot",slug:"/howtos/solutions/vector/gen-ai-chatbot",permalink:"/howtos/solutions/vector/gen-ai-chatbot",draft:!1,editUrl:"https://github.com/redis-developer/redis-developer/edit/master/docs/howtos/solutions/vector/gen-ai-chatbot/index-gen-ai-chatbot.mdx",tags:[],version:"current",lastUpdatedAt:1702667455,formattedLastUpdatedAt:"Dec 15, 2023",frontMatter:{id:"index-solutions-gen-ai-chatbot",title:"How to Build a GenAI Chatbot Using LangChain and Redis",sidebar_label:"How to Build a GenAI Chatbot Using LangChain and Redis",slug:"/howtos/solutions/vector/gen-ai-chatbot",authors:["prasan","will"]},sidebar:"docs",previous:{title:"How to Perform Vector Similarity Search Using Redis in NodeJS",permalink:"/howtos/solutions/vector/getting-started-vector"},next:{title:"How to build a Real-Time Leaderboard app Using Redis",permalink:"/howtos/leaderboard"}},m={},u=[{value:"What you will learn in this tutorial",id:"what-you-will-learn-in-this-tutorial",level:2},{value:"Terminology",id:"terminology",level:2},{value:"Microservices architecture for an e-commerce application",id:"microservices-architecture-for-an-e-commerce-application",level:2},{value:"E-commerce application frontend using Next.js and Tailwind",id:"e-commerce-application-frontend-using-nextjs-and-tailwind",level:2},{value:"Chatbot architecture",id:"chatbot-architecture",level:2},{value:"Flow diagram",id:"flow-diagram",level:3},{value:"Sample user prompt and AI response",id:"sample-user-prompt-and-ai-response",level:3},{value:"Database setup",id:"database-setup",level:2},{value:"Sample data",id:"sample-data",level:3},{value:"OpenAI embeddings seeding",id:"openai-embeddings-seeding",level:3},{value:"Setting up the chatbot API",id:"setting-up-the-chatbot-api",level:2},{value:"API end point",id:"api-end-point",level:3},{value:"API implementation",id:"api-implementation",level:3},{value:"Ready to use Redis for genAI chatbot?",id:"ready-to-use-redis-for-genai-chatbot",level:2},{value:"Further reading",id:"further-reading",level:2}],h={toc:u};function g(e){let{components:t,...l}=e;return(0,o.kt)("wrapper",(0,a.Z)({},h,l,{components:t,mdxType:"MDXLayout"}),(0,o.kt)(s.Z,{frontMatter:d,mdxType:"Authors"}),(0,o.kt)("h2",{id:"what-you-will-learn-in-this-tutorial"},"What you will learn in this tutorial"),(0,o.kt)("p",null,"In this tutorial, you'll learn how to build a GenAI chatbot using ",(0,o.kt)("inlineCode",{parentName:"p"},"LangChain")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Redis"),". You'll also learn how to use ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model to generate responses to user queries and how to use Redis to store and retrieve data."),(0,o.kt)("p",null,"Here's what's covered:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"E-Commerce App")," : A sample e-commerce application where users can search for products and ask questions about them, add them to their cart, and purchase them."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Chatbot Architecture")," : The architecture of the chatbot, including the flow diagram, sample user prompt and it's AI response."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Database setup")," : Generating OpenAI embeddings for products and storing them in Redis."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Setting up the chatbot API")," : Creating a chatbot API that uses OpenAI and Redis to answer user questions and recommend products.")),(0,o.kt)("h2",{id:"terminology"},"Terminology"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Generative AI"),", also known as ",(0,o.kt)("strong",{parentName:"p"},"GenAI"),", is a category of artificial intelligence that specializes in creating new content based on pre-existing data. It can generate a wide array of content types, including text, images, videos, sounds, code, 3D designs, and other media formats. Unlike traditional AI models that focus on analyzing and interpreting existing data, GenAI models learn from existing data and then use their knowledge to generate something entirely new."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("a",{parentName:"strong",href:"https://js.langchain.com"},"LangChain"))," is an innovative library for building language model applications. It offers a structured way to combine different components like language models (e.g., OpenAI's models), storage solutions (like Redis), and custom logic. This modular approach facilitates the creation of sophisticated AI applications, including chatbots."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("a",{parentName:"strong",href:"https://openai.com/"},"OpenAI"))," provides advanced language models like GPT-3, which have revolutionized the field with their ability to understand and generate human-like text. These models form the backbone of many modern AI applications, including chatbots."),(0,o.kt)("h2",{id:"microservices-architecture-for-an-e-commerce-application"},"Microservices architecture for an e-commerce application"),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)(r.default,{mdxType:"InitialMicroservicesArchitecture"}),(0,o.kt)("h2",{id:"e-commerce-application-frontend-using-nextjs-and-tailwind"},"E-commerce application frontend using Next.js and Tailwind"),(0,o.kt)(i.default,{mdxType:"MicroservicesEcommerceAIDesign"}),(0,o.kt)("h2",{id:"chatbot-architecture"},"Chatbot architecture"),(0,o.kt)("h3",{id:"flow-diagram"},"Flow diagram"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"flow diagram",src:n(5402).Z,width:"1801",height:"943"})),(0,o.kt)("p",null,"1> ",(0,o.kt)("strong",{parentName:"p"},"Create Standalone Question"),": Create a standalone question using ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model."),(0,o.kt)("p",null,"A standalone question is just a question reduced to the minimum number of words needed to express the request for information."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"//Example\nuserQuestion =\n \"I'm thinking of buying one of your T-shirts but I need to know what your returns policy is as some T-shirts just don't fit me and I don't want to waste money.\";\n\n//semanticMeaning of above question\nstandAloneQuestion = 'What is your return policy?';\n")),(0,o.kt)("p",null,"2> ",(0,o.kt)("strong",{parentName:"p"},"Create Embeddings for Question"),": Once the question is created, ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model generates an embedding for the question."),(0,o.kt)("p",null,"3> ",(0,o.kt)("strong",{parentName:"p"},"Find Nearest Match in Redis Vector Store"),": The embedding is then used to query ",(0,o.kt)("inlineCode",{parentName:"p"},"Redis")," vector store. The system searches for the nearest match to the question embedding among stored vectors"),(0,o.kt)("p",null,"4> ",(0,o.kt)("strong",{parentName:"p"},"Get Answer"),": With the user initial question, the nearest match from the vector store, and the conversation memory, ",(0,o.kt)("inlineCode",{parentName:"p"},"OpenAI's")," language model generates an answer. This answer is then provided to the user."),(0,o.kt)("p",null,"Note : The system maintains a conversation memory, which tracks the ongoing conversation's context. This memory is crucial for ensuring the continuity and relevance of the conversation."),(0,o.kt)("p",null,"5> ",(0,o.kt)("strong",{parentName:"p"},"User Receives Answer"),": The answer is sent back to the user, completing the interaction cycle. The conversation memory is updated with this latest exchange to inform future responses."),(0,o.kt)("h3",{id:"sample-user-prompt-and-ai-response"},"Sample user prompt and AI response"),(0,o.kt)("p",null,"Say, OriginalQuestion of user is as follows:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"I am looking for a watch, Can you recommend anything for formal occasions with price under 50 dollars?")),(0,o.kt)("p",null,"Converted standaloneQuestion by openAI is as follows:"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"What watches do you recommend for formal occasions with a price under $50?")),(0,o.kt)("p",null,"After vector similarity search on ",(0,o.kt)("strong",{parentName:"p"},"Redis"),", we get the following similarProducts:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},"similarProducts = [\n {\n pageContent: ` Product details are as follows:\n productId: 11005.\n productDisplayName: Puma Men Visor 3HD Black Watch.\n price: 5495 ...`,\n metadata: { productId: '11005' },\n },\n {\n pageContent: ` Product details are as follows:\n productId: 11006.\n productDisplayName: Puma Men Race Luminous Black Chronograph Watch.\n price: 7795 ... `,\n metadata: { productId: '11006' },\n },\n];\n")),(0,o.kt)("p",null,"The final openAI response with above context and earlier chat history (if any) is as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},'answer = `I recommend two watches for formal occasions with a price under $50. \n\nFirst, we have the Puma Men Visor 3HD Black Watch priced at $54.95. This watch features a heavy-duty design with a stylish dial and chunky casing, giving it a tough appearance - perfect for navigating the urban jungle. It has a square dial shape and a 32 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters. \n\nSecond, we have the Puma Men Race Luminous Black Chronograph Watch priced at $77.95. This watch also features a heavy-duty design with a stylish dial and chunky casing. It has a round dial shape and a 40 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters. \n\nBoth these watches from Puma are perfect for formal occasions and are priced under $50. I hope this helps, and please let me know if you have any other questions!`;\n')),(0,o.kt)("h2",{id:"database-setup"},"Database setup"),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Sign up for an ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://platform.openai.com/"},"OpenAI account"))," to get your API key to be used in the demo (add OPEN_AI_API_KEY variable in .env file). You can also refer to the ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://platform.openai.com/docs/api-reference/introduction"},"OpenAI API documentation"))," for more information.")),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)("h3",{id:"sample-data"},"Sample data"),(0,o.kt)("p",null,"For the purposes of this tutorial, let's consider a simplified e-commerce context. The ",(0,o.kt)("inlineCode",{parentName:"p"},"products")," JSON provided offers a glimpse into AI search functionalities we'll be operating on."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/fashion-dataset/001/products/*.json"',title:'"database/fashion-dataset/001/products/*.json"'},"const products = [\n {\n productId: '11000',\n price: 3995,\n productDisplayName: 'Puma Men Slick 3HD Yellow Black Watches',\n variantName: 'Slick 3HD Yellow',\n brandName: 'Puma',\n ageGroup: 'Adults-Men',\n gender: 'Men',\n displayCategories: 'Accessories',\n masterCategory_typeName: 'Accessories',\n subCategory_typeName: 'Watches',\n styleImages_default_imageURL:\n 'http://host.docker.internal:8080/images/11000.jpg',\n productDescriptors_description_value:\n '

Stylish and comfortable, ...',\n stockQty: 25,\n },\n //...\n];\n")),(0,o.kt)("h3",{id:"openai-embeddings-seeding"},"OpenAI embeddings seeding"),(0,o.kt)("p",null,"Below is the sample code to seed ",(0,o.kt)("inlineCode",{parentName:"p"},"products")," data as openAI embeddings into Redis."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="database/src/open-ai.ts"',title:'"database/src/open-ai.ts"'},"import { Document } from 'langchain/document';\nimport { OpenAIEmbeddings } from 'langchain/embeddings/openai';\nimport { RedisVectorStore } from 'langchain/vectorstores/redis';\n\n/**\n * Adds OpenAI embeddings to Redis for the given products.\n *\n * @param _products - An array of (ecommerce) products.\n * @param _redisClient - The Redis client used to connect to the Redis server.\n * @param _openAIApiKey - The API key for accessing the OpenAI service.\n */\nconst addOpenAIEmbeddingsToRedis = async (\n _products,\n _redisClient,\n _openAIApiKey,\n) => {\n if (_products?.length > 0 && _redisClient && _openAIApiKey) {\n // Check if the data is already seeded\n const existingKeys = await _redisClient.keys('openAIProducts:*');\n if (existingKeys.length > 0) {\n console.log('seeding openAIEmbeddings skipped !');\n return;\n }\n\n const vectorDocs: Document[] = [];\n // Create a document for each product\n for (let product of _products) {\n let doc = new Document({\n metadata: {\n productId: product.productId,\n },\n pageContent: ` Product details are as follows:\n productId: ${product.productId}.\n \n productDisplayName: ${product.productDisplayName}.\n \n price: ${product.price}.\n \n variantName: ${product.variantName}.\n \n brandName: ${product.brandName}.\n \n ageGroup: ${product.ageGroup}.\n \n gender: ${product.gender}.\n \n productColors: ${product.productColors}\n \n Category: ${product.displayCategories}, ${product.masterCategory_typeName} - ${product.subCategory_typeName}\n \n productDescription: ${product.productDescriptors_description_value}`,\n });\n\n vectorDocs.push(doc);\n }\n\n // Create a new OpenAIEmbeddings instance\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: _openAIApiKey,\n });\n // Add the documents to the RedisVectorStore\n const vectorStore = await RedisVectorStore.fromDocuments(\n vectorDocs,\n embeddings,\n {\n redisClient: _redisClient,\n indexName: 'openAIProductsIdx',\n keyPrefix: 'openAIProducts:',\n },\n );\n console.log('seeding OpenAIEmbeddings completed');\n }\n};\n")),(0,o.kt)("p",null,"You can observe openAIProducts JSON in RedisInsight:"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight AI products",src:n(17984).Z,width:"1920",height:"1054"})),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Download ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://redis.com/redis-enterprise/redis-insight/"},"RedisInsight"))," to visually explore your Redis data or to engage with raw Redis commands in the workbench.")),(0,o.kt)("h2",{id:"setting-up-the-chatbot-api"},"Setting up the chatbot API"),(0,o.kt)(c.default,{mdxType:"SourceCode"}),(0,o.kt)("p",null,"Once products data is seeded as openAI embeddings into Redis, we can create a ",(0,o.kt)("inlineCode",{parentName:"p"},"chatbot")," API to answer user questions and recommend products."),(0,o.kt)("h3",{id:"api-end-point"},"API end point"),(0,o.kt)("p",null,"The code that follows shows an example API request and response for the ",(0,o.kt)("inlineCode",{parentName:"p"},"chatBot")," API:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'POST http://localhost:3000/products/chatBot\n{\n "userMessage":"I am looking for a watch, Can you recommend anything for formal occasions with price under 50 dollars?"\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Response")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "data": "I recommend two watches for formal occasions with a price under $50.\n\n First, we have the Puma Men Visor 3HD Black Watch priced at $54.95. This watch features a heavy-duty design with a stylish dial and chunky casing, giving it a tough appearance - perfect for navigating the urban jungle. It has a square dial shape and a 32 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters.\n\n Second, we have the Puma Men Race Luminous Black Chronograph Watch priced at $77.95. This watch also features a heavy-duty design with a stylish dial and chunky casing. It has a round dial shape and a 40 mm case diameter. The watch comes with a 2-year warranty and is water-resistant up to 50 meters.\n\n Both these watches from Puma are perfect for formal occasions and are priced under $50. I hope this helps, and please let me know if you have any other questions!",\n\n "error": null,\n "auth": "SES_54f211db-50a7-45df-8067-c3dc4272beb2"\n}\n')),(0,o.kt)("h3",{id:"api-implementation"},"API implementation"),(0,o.kt)("p",null,"When you make a request, it goes through the API gateway to the ",(0,o.kt)("inlineCode",{parentName:"p"},"products")," service. Ultimately, it ends up calling an ",(0,o.kt)("inlineCode",{parentName:"p"},"chatBotMessage")," function which looks as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"import {\n ChatOpenAI,\n ChatOpenAICallOptions,\n} from 'langchain/chat_models/openai';\nimport { PromptTemplate } from 'langchain/prompts';\nimport { OpenAIEmbeddings } from 'langchain/embeddings/openai';\nimport { RedisVectorStore } from 'langchain/vectorstores/redis';\nimport { StringOutputParser } from 'langchain/schema/output_parser';\nimport { Document } from 'langchain/document';\n\nlet llm: ChatOpenAI;\n\nconst chatBotMessage = async (\n _userMessage: string,\n _sessionId: string,\n _openAIApiKey: string,\n) => {\n const CHAT_BOT_LOG = 'CHAT_BOT_LOG_STREAM';\n const redisWrapperInst = getRedis();\n\n // Add user message to chat history\n const chatHistoryName = 'chatHistory:' + _sessionId;\n redisWrapperInst.addItemToList(\n chatHistoryName,\n 'userMessage: ' + _userMessage,\n );\n // add log\n addMessageToStream(\n { name: 'originalQuestion', comments: _userMessage },\n CHAT_BOT_LOG,\n );\n\n // (1) Create a standalone question\n const standaloneQuestion = await convertToStandAloneQuestion(\n _userMessage,\n _sessionId,\n _openAIApiKey,\n );\n // add log\n addMessageToStream(\n { name: 'standaloneQuestion', comments: standaloneQuestion },\n CHAT_BOT_LOG,\n );\n\n // (2) Get similar products from Redis\n const similarProducts = await getSimilarProductsByVSS(\n standaloneQuestion,\n _openAIApiKey,\n );\n if (similarProducts?.length) {\n // add log\n addMessageToStream(\n { name: 'similarProducts', comments: JSON.stringify(similarProducts) },\n CHAT_BOT_LOG,\n );\n }\n\n // Combine the product details into a single document\n const productDetails = combineVectorDocuments(similarProducts);\n console.log('productDetails:', productDetails);\n\n // (3) Get answer from OpenAI\n const answer = await convertToAnswer(\n _userMessage,\n standaloneQuestion,\n productDetails,\n _sessionId,\n _openAIApiKey,\n );\n // add log\n addMessageToStream({ name: 'answer', comments: answer }, CHAT_BOT_LOG);\n\n // Add answer to chat history\n redisWrapperInst.addItemToList(\n chatHistoryName,\n 'openAIMessage(You): ' + answer,\n );\n\n return answer;\n};\n")),(0,o.kt)("p",null,"Below function converts the userMessage to standaloneQuestion using ",(0,o.kt)("inlineCode",{parentName:"p"},"openAI")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"// (1) Create a standalone question\nconst convertToStandAloneQuestion = async (\n _userQuestion: string,\n _sessionId: string,\n _openAIApiKey: string,\n) => {\n const llm = getOpenAIInstance(_openAIApiKey);\n\n const chatHistory = await getChatHistory(_sessionId);\n\n const standaloneQuestionTemplate = `Given some conversation history (if any) and a question, convert it to a standalone question. \n ***********************************************************\n conversation history: \n ${chatHistory}\n ***********************************************************\n question: {question} \n standalone question:`;\n\n const standaloneQuestionPrompt = PromptTemplate.fromTemplate(\n standaloneQuestionTemplate,\n );\n\n const chain = standaloneQuestionPrompt\n .pipe(llm)\n .pipe(new StringOutputParser());\n\n const response = await chain.invoke({\n question: _userQuestion,\n });\n\n return response;\n};\nconst getOpenAIInstance = (_openAIApiKey: string) => {\n if (!llm) {\n llm = new ChatOpenAI({\n openAIApiKey: _openAIApiKey,\n });\n }\n return llm;\n};\n\nconst getChatHistory = async (_sessionId: string, _separator?: string) => {\n let chatHistory = '';\n if (!_separator) {\n _separator = '\\n\\n';\n }\n if (_sessionId) {\n const redisWrapperInst = getRedis();\n const chatHistoryName = 'chatHistory:' + _sessionId;\n const items = await redisWrapperInst.getAllItemsFromList(chatHistoryName);\n\n if (items?.length) {\n chatHistory = items.join(_separator);\n }\n }\n return chatHistory;\n};\nconst combineVectorDocuments = (\n _vectorDocs: Document[],\n _separator?: string,\n) => {\n if (!_separator) {\n _separator = '\\n\\n --------------------- \\n\\n';\n }\n return _vectorDocs.map((doc) => doc.pageContent).join(_separator);\n};\n")),(0,o.kt)("p",null,"Below function uses ",(0,o.kt)("inlineCode",{parentName:"p"},"Redis")," to find similar products for the standaloneQuestion"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"// (2) Get similar products from Redis\nconst getSimilarProductsByVSS = async (\n _standAloneQuestion: string,\n _openAIApiKey: string,\n) => {\n const client = getNodeRedisClient();\n\n const embeddings = new OpenAIEmbeddings({\n openAIApiKey: _openAIApiKey,\n });\n const vectorStore = new RedisVectorStore(embeddings, {\n redisClient: client,\n indexName: 'openAIProductsIdx',\n keyPrefix: 'openAIProducts:',\n });\n\n const KNN = 3;\n /* Simple standalone search in the vector DB */\n const vectorDocs = await vectorStore.similaritySearch(\n _standAloneQuestion,\n KNN,\n );\n\n return vectorDocs;\n};\n")),(0,o.kt)("p",null,"Below function uses ",(0,o.kt)("inlineCode",{parentName:"p"},"openAI")," to convert the standaloneQuestion, similar products from Redis and other context to a human understandable answer."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts",metastring:'title="server/src/services/products/src/open-ai-prompt.ts"',title:'"server/src/services/products/src/open-ai-prompt.ts"'},"// (3) Get answer from OpenAI\nconst convertToAnswer = async (\n _originalQuestion: string,\n _standAloneQuestion: string,\n _productDetails: string,\n _sessionId: string,\n _openAIApiKey: string,\n) => {\n const llm = getOpenAIInstance(_openAIApiKey);\n\n const chatHistory = await getChatHistory(_sessionId);\n\n const answerTemplate = `\n Please assume the persona of a retail shopping assistant for this conversation.\n Use a friendly tone, and assume the target audience are normal people looking for a product in a ecommerce website.\n\n ***********************************************************\n ${\n chatHistory\n ? `\n Conversation history between user and you is : \n ${chatHistory}\n `\n : ''\n }\n ***********************************************************\n OriginalQuestion of user is : {originalQuestion}\n ***********************************************************\n converted stand alone question is : {standAloneQuestion}\n ***********************************************************\n resulting details of products for the stand alone question are :\n {productDetails}\n Note : Different product details are separated by \"---------------------\" (if any) \n ***********************************************************\n Answer the question based on the context provided and the conversation history.\n \n If you don't know the answer, please direct the questioner to email help@redis.com. Don't try to suggest any product out of context as it may not be in the store.\n\n Let the answer include product display name, price and optional other details based on question asked.\n\n Let the product display name be a link like productDisplayName \n so that user can click on it and go to the product page with help of productId.\n \n answer: `;\n\n const answerPrompt = PromptTemplate.fromTemplate(answerTemplate);\n const chain = answerPrompt.pipe(llm).pipe(new StringOutputParser());\n\n const response = await chain.invoke({\n originalQuestion: _originalQuestion,\n standAloneQuestion: _standAloneQuestion,\n productDetails: _productDetails,\n });\n\n return response;\n};\n")),(0,o.kt)("p",null,"You can observe chat history and intermediate chat logs in RedisInsight:"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight chat history",src:n(42614).Z,width:"1920",height:"1056"})),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Redis Insight chat log",src:n(77193).Z,width:"1920",height:"1052"})),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Download ",(0,o.kt)("u",null,(0,o.kt)("a",{parentName:"p",href:"https://redis.com/redis-enterprise/redis-insight/"},"RedisInsight"))," to visually explore your Redis data or to engage with raw Redis commands in the workbench.")),(0,o.kt)("h2",{id:"ready-to-use-redis-for-genai-chatbot"},"Ready to use Redis for genAI chatbot?"),(0,o.kt)("p",null,"Building a GenAI chatbot using LangChain and Redis involves integrating advanced AI models with efficient storage solutions. This tutorial covers the fundamental steps and code needed to develop a chatbot capable of handling e-commerce queries. With these tools, you can create a responsive, intelligent chatbot for a variety of applications"),(0,o.kt)("h2",{id:"further-reading"},"Further reading"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"/howtos/solutions/vector/getting-started-vector"},"Perform vector similarity search using Redis"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/get_started/quickstart"},"LangChain JS")),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://scrimba.com/learn/langchain"},"Learn LangChain")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"https://js.langchain.com/docs/integrations/vectorstores/redis"},"LangChain redis integration")))))}g.isMDXComponent=!0},7050:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/01-dashboard-30dbf86a0b22aeecd106670087599066.png"},99609:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/02-ai-bot-c7989293733f79cedcc9f475171c9b03.png"},73064:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/03-ai-bot-product-ed8e13e4a32f72b952d683473a4c4d0f.png"},15030:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/04-shopping-cart-5445685389780e76ba7135e47f0ad20b.png"},14065:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/05-order-history-fa1ebafcf8ac4ee027f5616a00044ee9.png"},37740:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/06-admin-charts-5ae00e6182be0b4ada06049f5d18d0aa.png"},96127:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/07-admin-top-trending-941390270b22d7b4243b386af50ec743.png"},5402:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/chat-bot-flow-c7e389bbe40a85354630e0ec8b45243e.png"},17984:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-ai-products-43d2d9e8851e513777b5390c8c385c26.png"},42614:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-chat-history-64378d953fada2307e36455db66ec5d6.png"},77193:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/redis-insight-chat-log-ab79e77e0998eadc2bb5b124911105ce.png"}}]); \ No newline at end of file diff --git a/assets/js/main.16aceb96.js b/assets/js/main.16aceb96.js deleted file mode 100644 index 69fbca8d99..0000000000 --- a/assets/js/main.16aceb96.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.16aceb96.js.LICENSE.txt */ -(self.webpackChunkredis_developer_hub=self.webpackChunkredis_developer_hub||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>h});var r=n(67294),o=n(87462),a=n(68356),i=n.n(a),s=n(16887);const c={"00d7f298":[()=>Promise.all([n.e(532),n.e(1735)]).then(n.bind(n,65733)),"@site/docs/howtos/herokunodejs/index-herokunodejs.mdx",65733],"03506951":[()=>n.e(5653).then(n.bind(n,31788)),"@site/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip.mdx",31788],"0545e01d":[()=>Promise.all([n.e(532),n.e(2163)]).then(n.bind(n,1763)),"@site/docs/howtos/redisgraph/getting-started/index-gettingstarted.mdx",1763],"0566ee4e":[()=>n.e(9993).then(n.bind(n,99453)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-many-skus.mdx",99453],"0776bfb3":[()=>Promise.all([n.e(532),n.e(3941),n.e(9636)]).then(n.bind(n,9613)),"@site/docs/create/docker/index-docker.mdx",9613],"07a6fe21":[()=>Promise.all([n.e(532),n.e(3941),n.e(6972)]).then(n.bind(n,70429)),"@site/docs/develop/java/spring/redis-and-spring-course/index-redis-and-spring-course.mdx",70429],"085ffbd7":[()=>Promise.all([n.e(532),n.e(370)]).then(n.bind(n,36622)),"@site/docs/howtos/quick-start/cheat-sheets/lists.mdx",36622],"098330c0":[()=>n.e(1317).then(n.bind(n,94163)),"@site/docs/create/cloud/azure/index-azure.mdx",94163],"099d618a":[()=>Promise.all([n.e(532),n.e(2626)]).then(n.bind(n,1434)),"@site/docs/develop/node/node-crash-course/advancedstreams/index-advancedstreams.mdx",1434],"0abd8cd0":[()=>Promise.all([n.e(532),n.e(7992)]).then(n.bind(n,18465)),"@site/docs/develop/python/redis-om/index-redis-om.mdx",18465],"0b7ca231":[()=>Promise.all([n.e(532),n.e(8922)]).then(n.bind(n,45400)),"@site/docs/howtos/redisgraph/explore-python-code/index-explorepythoncode.mdx",45400],"0b9646e8":[()=>Promise.all([n.e(532),n.e(3941),n.e(1324)]).then(n.bind(n,67417)),"@site/docs/create/heroku/index-heroku.mdx",67417],"0c264ecc":[()=>Promise.all([n.e(532),n.e(3294)]).then(n.bind(n,32875)),"@site/docs/operate/provisioning/terraform/index-terraform.mdx",32875],"0c306a96":[()=>Promise.all([n.e(532),n.e(6667)]).then(n.bind(n,81891)),"@site/docs/howtos/caching/index-caching.mdx",81891],"0c9e8015":[()=>Promise.all([n.e(532),n.e(3941),n.e(4092)]).then(n.bind(n,26136)),"@site/docs/develop/java/spring/rate-limiting/index-ratelimiting.mdx",26136],"0ec1cc91":[()=>n.e(4074).then(n.bind(n,36773)),"@site/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx",36773],"0f0e7497":[()=>n.e(8361).then(n.bind(n,39097)),"@site/docs/operate/redis-at-scale/observability/exercise-1/index-exercise-1.mdx",39097],"0fdc98ff":[()=>n.e(9743).then(n.bind(n,33123)),"@site/docs/guides/import-data.mdx",33123],"106fc9f0":[()=>n.e(4705).then(n.bind(n,49998)),"@site/docs/tools/index-tools.mdx",49998],"110bbf9d":[()=>Promise.all([n.e(532),n.e(5784)]).then(n.bind(n,82937)),"@site/docs/howtos/solutions/caching-architecture/cache-prefetching/index-cache-prefetching.mdx",82937],"11166ec1":[()=>n.e(9783).then(n.bind(n,31986)),"@site/docs/howtos/moviesdatabase/aggregation/index-aggregation.mdx",31986],"12853b3b":[()=>Promise.all([n.e(532),n.e(6047)]).then(n.bind(n,94287)),"@site/docs/develop/node/node-crash-course/sessionstorage/index-sessionstorage.mdx",94287],"129ce714":[()=>n.e(3015).then(n.bind(n,10500)),"@site/docs/howtos/moviesdatabase/import/index-import.mdx",10500],"1341f4ef":[()=>Promise.all([n.e(532),n.e(5312)]).then(n.bind(n,20376)),"@site/docs/howtos/redisgraph/csvtograph/index-csvtograph.mdx",20376],"13ca8dc8":[()=>Promise.all([n.e(532),n.e(6502)]).then(n.bind(n,63046)),"@site/docs/develop/dotnet/index-dotnet.mdx",63046],"14612fe5":[()=>n.e(4195).then(n.bind(n,5988)),"@site/docs/operate/redis-at-scale/persistence-and-durability/index-persistence-and-durability.mdx",5988],"16138ba5":[()=>Promise.all([n.e(532),n.e(6347)]).then(n.bind(n,75345)),"@site/docs/operate/orchestration/kubernetes-gke/index-kubernetes-gke.mdx",75345],"163f4d81":[()=>n.e(2525).then(n.bind(n,58617)),"@site/docs/develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions.md",58617],"165403c2":[()=>n.e(5815).then(n.bind(n,67509)),"@site/docs/howtos/quick-start/cheat-sheets/triggers-and-functions.mdx",67509],"169d51e4":[()=>Promise.all([n.e(532),n.e(3941),n.e(2421)]).then(n.bind(n,68210)),"@site/docs/create/aws/index-aws.mdx",68210],"16ae7048":[()=>Promise.all([n.e(532),n.e(9933)]).then(n.bind(n,38758)),"@site/docs/howtos/solutions/caching-architecture/write-through/index-write-through.mdx",38758],"1756b4ab":[()=>Promise.all([n.e(532),n.e(7607)]).then(n.bind(n,47562)),"@site/docs/develop/node/node-crash-course/runningtheapplication/index-runningtheapplication.mdx",47562],17896441:[()=>Promise.all([n.e(532),n.e(3941),n.e(7918)]).then(n.bind(n,12504)),"@theme/DocItem",12504],"18050ae3":[()=>n.e(6425).then(n.bind(n,14353)),"@site/docs/operate/redis-at-scale/high-availability/exercise-2/index-exercise-2.mdx",14353],"18719bcf":[()=>n.e(8314).then(n.bind(n,60277)),"@site/docs/howtos/solutions/microservices/common-data/microservices-ecommerce-old.mdx",60277],"18edca16":[()=>n.e(5516).then(n.bind(n,51077)),"@site/docs/create/cloud/rediscloud/images/README.md",51077],"1be78505":[()=>Promise.all([n.e(532),n.e(3614),n.e(9514)]).then(n.bind(n,19963)),"@theme/DocPage",19963],"1cf06b0d":[()=>Promise.all([n.e(532),n.e(409)]).then(n.bind(n,26437)),"@site/docs/get-involved/hacktoberfest/index-hacktoberfest.mdx",26437],"1d1b3f81":[()=>Promise.all([n.e(532),n.e(4641)]).then(n.bind(n,68367)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_2/index-lesson_2.mdx",68367],"1dc33e9c":[()=>Promise.all([n.e(532),n.e(87)]).then(n.bind(n,28407)),"@site/docs/howtos/popupstore/index-popupstore.mdx",28407],"1df93b7f":[()=>Promise.all([n.e(3614),n.e(6066),n.e(3237)]).then(n.bind(n,7367)),"@site/src/pages/index.tsx",7367],"1e115aba":[()=>n.e(149).then(n.bind(n,72656)),"@site/docs/create/azure/portal/index-azure-portal.mdx",72656],"1ef24e58":[()=>n.e(464).then(n.bind(n,87253)),"@site/docs/develop/java/spring/redis-om/index-redis-om-spring-hash.mdx",87253],"2123ba4c":[()=>Promise.all([n.e(532),n.e(6709)]).then(n.bind(n,19790)),"@site/docs/explore/redisdatasource/index-redisdatasource.mdx",19790],"214a573e":[()=>n.e(6973).then(n.bind(n,94233)),"@site/docs/operate/redis-at-scale/persistence-and-durability/exercise/index-exercise.mdx",94233],"21bf2b11":[()=>Promise.all([n.e(532),n.e(1380)]).then(n.bind(n,32936)),"@site/docs/howtos/quick-start/cheat-sheets/strings.mdx",32936],"223019eb":[()=>Promise.all([n.e(532),n.e(8338)]).then(n.bind(n,12538)),"@site/docs/howtos/solutions/microservices/caching/index-caching.mdx",12538],"23200c1b":[()=>Promise.all([n.e(532),n.e(5615)]).then(n.bind(n,83339)),"@site/docs/get-involved/redis-insiders/stevan-thomas/index-stevan-thomas.mdx",83339],"2601a326":[()=>Promise.all([n.e(532),n.e(6553)]).then(n.bind(n,50509)),"@site/docs/develop/java/spring/redis-om/index-redis-om-spring-json.mdx",50509],"265284fc":[()=>n.e(3901).then(n.bind(n,80880)),"@site/docs/howtos/solutions/mobile-banking/common-mb/data-seeding.mdx",80880],"27dc3412":[()=>n.e(9032).then(n.bind(n,664)),"@site/docs/create/cloud/images/README.md",664],"28193d1c":[()=>n.e(3482).then(n.bind(n,80990)),"@site/docs/howtos/solutions/vector/common-ai/microservices-ecommerce-ai.mdx",80990],"28b9548b":[()=>n.e(5146).then(n.bind(n,48781)),"@site/docs/howtos/redisgraph/redisgraph-cheatsheet/index-redisgraph-cheatsheet.mdx",48781],"29eff2aa":[()=>n.e(4698).then(n.bind(n,46598)),"@site/docs/ebooks/nosql-data-modeling-patterns.mdx",46598],"2b53ff98":[()=>n.e(8403).then(n.bind(n,94319)),"@site/docs/guides/import/database-migration-aws-elasticache-redis-enterprise-cloud.mdx",94319],"2b69ed49":[()=>n.e(7719).then(n.bind(n,75389)),"@site/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old.mdx",75389],"2bc54e2b":[()=>Promise.all([n.e(532),n.e(911)]).then(n.bind(n,49118)),"@site/docs/howtos/socialnetwork/index-socialnetwork.mdx",49118],"2c06bb79":[()=>n.e(1906).then(n.bind(n,67628)),"@site/docs/create/cloud/gcp/index-gcp.mdx",67628],"2c83c4e0":[()=>Promise.all([n.e(532),n.e(3108)]).then(n.bind(n,63606)),"@site/docs/howtos/herokupython/index-herokupython.mdx",63606],"2cac92cf":[()=>n.e(7809).then(n.bind(n,22581)),"@site/docs/operate/redis-at-scale/scalability/exercise-1/index-exercise-1.mdx",22581],"2d198a95":[()=>Promise.all([n.e(532),n.e(6365)]).then(n.bind(n,16014)),"@site/docs/develop/java/spring/rate-limiting/fixed-window/index-fixed-window-reactive-lua.mdx",16014],"2d271c04":[()=>n.e(3762).then(n.bind(n,92642)),"@site/docs/develop/dotnet/redis-om-dotnet/aggregations/intro/intro.md",92642],"2f1cd5d9":[()=>n.e(247).then(n.bind(n,56002)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/api/increment-sku.mdx",56002],"31350f16":[()=>n.e(5201).then(n.bind(n,7350)),"@site/docs/operate/redis-at-scale/talking-to-redis/redis-server-overview/index-redis-server-overview.mdx",7350],"335cbbbb":[()=>Promise.all([n.e(532),n.e(3941),n.e(1065)]).then(n.bind(n,18331)),"@site/docs/get-involved/index-getinvolved.mdx",18331],"3483a674":[()=>Promise.all([n.e(532),n.e(763)]).then(n.bind(n,1337)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise.mdx",1337],"3720c009":[()=>Promise.all([n.e(532),n.e(3751)]).then(n.bind(n,9861)),"@theme/DocTagsListPage",9861],"389b810a":[()=>n.e(8760).then(n.bind(n,77455)),"@site/docs/howtos/moviesdatabase/create/index-create.mdx",77455],"3962b4b6":[()=>n.e(3334).then(n.bind(n,24546)),"@site/docs/operate/redis-at-scale/high-availability/index-high-availability.mdx",24546],"3b0e0d3a":[()=>n.e(7502).then(n.bind(n,6729)),"@site/docs/guides/data-modeling/index-data-modeling.mdx",6729],"3b168288":[()=>Promise.all([n.e(532),n.e(8359)]).then(n.bind(n,62328)),"@site/docs/get-involved/redis-insiders/moiz-kapasi/index-moiz-kapasi.mdx",62328],"3bb72ea1":[()=>Promise.all([n.e(532),n.e(2302)]).then(n.bind(n,69683)),"@site/docs/develop/node/node-crash-course/redisjson/index-redisjson.mdx",69683],"3c066edc":[()=>n.e(1014).then(n.bind(n,45452)),"@site/docs/ebooks/three-caching-design-patterns.mdx",45452],"3d36e868":[()=>n.e(8879).then(n.bind(n,62462)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-many-skus.mdx",62462],"405b4698":[()=>Promise.all([n.e(532),n.e(8087)]).then(n.bind(n,8798)),"@site/docs/create/aws/terraform/index-terraform.mdx",8798],"4141cbdd":[()=>Promise.all([n.e(532),n.e(1698)]).then(n.bind(n,73956)),"@site/docs/develop/node/node-crash-course/redisearch/index-redisearch.mdx",73956],"42f12bbb":[()=>n.e(9774).then(n.bind(n,36716)),"@site/docs/modules/index-modules.mdx",36716],"434536ad":[()=>Promise.all([n.e(532),n.e(3941),n.e(6221)]).then(n.bind(n,95544)),"@site/docs/develop/node/index-node.mdx",95544],"4393e4bc":[()=>n.e(9074).then(n.bind(n,41514)),"@site/docs/howtos/solutions/real-time-inventory/common-rti/additional-resources.mdx",41514],"44556e56":[()=>n.e(7422).then(n.bind(n,92388)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-sku.mdx",92388],"4458e1ed":[()=>Promise.all([n.e(532),n.e(3941),n.e(9231)]).then(n.bind(n,43937)),"@site/docs/explore/import/index-import.mdx",43937],"4504686e":[()=>n.e(37).then(n.bind(n,98419)),"@site/docs/develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiting-middleware.md",98419],"45c1b0fa":[()=>Promise.all([n.e(532),n.e(4001)]).then(n.bind(n,99682)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_9/index-lesson_9.mdx",99682],"45db1732":[()=>Promise.all([n.e(532),n.e(821)]).then(n.bind(n,93343)),"@site/docs/explore/riot/index-riot.mdx",93343],"46b3dd76":[()=>n.e(7466).then(n.bind(n,5812)),"@site/docs/create/aws/redis-on-aws/images/README.md",5812],"46c09b1c":[()=>Promise.all([n.e(532),n.e(5979)]).then(n.bind(n,74476)),"@site/docs/howtos/quick-start/cheat-sheets/search-and-query.mdx",74476],47016385:[()=>Promise.all([n.e(532),n.e(9461)]).then(n.bind(n,62179)),"@site/docs/tools/riot/index-riot.mdx",62179],"470c62dd":[()=>Promise.all([n.e(532),n.e(3941),n.e(2801)]).then(n.bind(n,14020)),"@site/docs/develop/java/getting-started/index.md",14020],"4843ea13":[()=>n.e(1638).then(n.bind(n,2327)),"@site/docs/howtos/solutions/caching-architecture/common-caching/redis-gears.mdx",2327],"48f88c7a":[()=>n.e(7310).then(n.bind(n,10992)),"@site/docs/howtos/solutions/vector/common-ai/microservices-source-code-ai.mdx",10992],"49623f30":[()=>Promise.all([n.e(532),n.e(1358)]).then(n.bind(n,23426)),"@site/docs/howtos/solutions/caching-architecture/write-behind/index-write-behind.mdx",23426],"4c484ee6":[()=>Promise.all([n.e(532),n.e(8997)]).then(n.bind(n,86381)),"@site/docs/develop/java/spring/rate-limiting/fixed-window/index-fixed-window.mdx",86381],"4c591bd5":[()=>Promise.all([n.e(532),n.e(6779)]).then(n.bind(n,57013)),"@site/docs/howtos/solutions/microservices/interservice-communication/index-interservice-communication.mdx",57013],"4c958ddc":[()=>Promise.all([n.e(532),n.e(3941),n.e(7400)]).then(n.bind(n,60357)),"@site/docs/create/index-create.mdx",60357],"50b6ea97":[()=>Promise.all([n.e(532),n.e(3941),n.e(6615)]).then(n.bind(n,71114)),"@site/docs/create/azure/index-azure.mdx",71114],"51a7d035":[()=>Promise.all([n.e(532),n.e(1567)]).then(n.bind(n,43809)),"@site/docs/operate/redis-at-scale/talking-to-redis/index-talking-to-redis.mdx",43809],"51ede774":[()=>Promise.all([n.e(532),n.e(5426)]).then(n.bind(n,86299)),"@site/docs/howtos/quick-start/cheat-sheets/json.mdx",86299],"531549fe":[()=>n.e(9948).then(n.bind(n,73264)),"@site/docs/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search-with-distance.mdx",73264],"53b913eb":[()=>Promise.all([n.e(532),n.e(8006)]).then(n.bind(n,35814)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_7/index-lesson_7.mdx",35814],"5420bc6f":[()=>Promise.all([n.e(532),n.e(8969)]).then(n.bind(n,27394)),"@site/docs/create/heroku/portal/index-heroku.mdx",27394],"5450f727":[()=>Promise.all([n.e(532),n.e(7470)]).then(n.bind(n,23515)),"@site/docs/howtos/chatapp/index-chatapp.mdx",23515],"552ba15d":[()=>Promise.all([n.e(532),n.e(3114)]).then(n.bind(n,74731)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_4/index-lesson_4.mdx",74731],"55960ee5":[()=>n.e(4121).then(n.t.bind(n,88070,19)),"~docs/default/tags-list-current-prop-15a.json",88070],"55ccde6e":[()=>n.e(1601).then(n.bind(n,26306)),"@site/docs/develop/dotnet/redis-om-dotnet/aggregations/groups/groups.md",26306],"584963dc":[()=>Promise.all([n.e(532),n.e(3941),n.e(3610)]).then(n.bind(n,43766)),"@site/docs/create/kubernetes/index-kubernetes.mdx",43766],"59bac03b":[()=>n.e(7903).then(n.bind(n,30458)),"@site/docs/operate/redis-at-scale/talking-to-redis/client-performance-improvements/index-client-performance-improvements.mdx",30458],"5a6c6630":[()=>n.e(5599).then(n.bind(n,72586)),"@site/docs/get-involved/hacktoberfest/vincent-aceto-story/index-vincent-aceto-story.mdx",72586],"5b01a645":[()=>n.e(9342).then(n.bind(n,77753)),"@site/docs/operate/redis-at-scale/observability/introduction/index-introduction.mdx",77753],"5c25e952":[()=>Promise.all([n.e(532),n.e(4497)]).then(n.bind(n,45801)),"@site/docs/operate/orchestration/nodejs-nginx-redis/index-nodejs-nginx-redis.mdx",45801],"5d14e41e":[()=>Promise.all([n.e(532),n.e(1389)]).then(n.bind(n,1193)),"@site/docs/develop/java/spring/getting-started.mdx",1193],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,36809)),"@generated/docusaurus.config",36809],"5ef34981":[()=>Promise.all([n.e(532),n.e(8851)]).then(n.bind(n,92079)),"@site/docs/howtos/leaderboard/index-leaderboard.mdx",92079],"613fe82a":[()=>n.e(7338).then(n.bind(n,43420)),"@site/docs/howtos/moviesdatabase/advancedoption/index-advancedoption.mdx",43420],"6410f0dc":[()=>n.e(3451).then(n.bind(n,81374)),"@site/docs/howtos/moviesdatabase/install/index-install.mdx",81374],"642fde82":[()=>n.e(4).then(n.bind(n,56426)),"@site/docs/howtos/moviesdatabase/sampleapp/index-sampleapp.mdx",56426],64867942:[()=>Promise.all([n.e(532),n.e(3941),n.e(4597)]).then(n.bind(n,20041)),"@site/docs/guides/import/index-import.mdx",20041],"64f3f413":[()=>Promise.all([n.e(532),n.e(1059)]).then(n.bind(n,46850)),"@site/docs/develop/guides/netlify/getting-started/index-getting-started.mdx",46850],"651422d5":[()=>n.e(9023).then(n.bind(n,73002)),"@site/docs/create/cloud/aws/index-aws.mdx",73002],"67747c0c":[()=>Promise.all([n.e(532),n.e(9677)]).then(n.bind(n,77518)),"@site/docs/develop/node/node-crash-course/coursewrapup/index-coursewrapup.mdx",77518],"6980e26f":[()=>Promise.all([n.e(532),n.e(4974)]).then(n.bind(n,52574)),"@site/docs/get-involved/redis-insiders/index-redis-insiders.mdx",52574],"69c2ba4e":[()=>Promise.all([n.e(532),n.e(46)]).then(n.bind(n,74694)),"@site/docs/develop/node/node-crash-course/welcome/index-welcome.mdx",74694],"6b006b96":[()=>n.e(3186).then(n.bind(n,50638)),"@site/docs/howtos/moviesdatabase/index-moviesdatabase.mdx",50638],"6b968562":[()=>n.e(2551).then(n.bind(n,2585)),"@site/docs/create/images/README.md",2585],"6c249fdd":[()=>Promise.all([n.e(532),n.e(6216)]).then(n.bind(n,79034)),"@site/docs/howtos/frauddetection/index-frauddetection.mdx",79034],"6c272831":[()=>Promise.all([n.e(532),n.e(3941),n.e(4936)]).then(n.bind(n,35077)),"@site/docs/howtos/solutions/index-solutions.mdx",35077],"6e373ae3":[()=>Promise.all([n.e(532),n.e(4518)]).then(n.bind(n,42828)),"@site/docs/howtos/solutions/real-time-inventory/local-inventory-search/index-rti-local-inventory-search.mdx",42828],"70771f47":[()=>Promise.all([n.e(532),n.e(9156)]).then(n.bind(n,37870)),"@site/docs/develop/node/node-crash-course/introductiontomodules/index-introductiontomodules.mdx",37870],"70a5ec54":[()=>Promise.all([n.e(532),n.e(2399)]).then(n.bind(n,94410)),"@site/docs/create/aws/chatapp/index-chatapp.mdx",94410],"710646cd":[()=>Promise.all([n.e(532),n.e(1280)]).then(n.bind(n,84614)),"@site/docs/develop/node/node-crash-course/redisbloom/index-redisbloom.mdx",84614],71898787:[()=>n.e(3551).then(n.bind(n,20507)),"@site/docs/develop/java/spring/rate-limiting/fixed-window/index-fixed-window-reactive-gears.mdx",20507],"730e35c4":[()=>Promise.all([n.e(532),n.e(2659)]).then(n.bind(n,27813)),"@site/docs/howtos/antipatterns/index-antipatterns.mdx",27813],"73e252ed":[()=>n.e(913).then(n.bind(n,94791)),"@site/docs/operate/redis-at-scale/talking-to-redis/configuring-a-redis-server/index-configuring-a-redis-server.mdx",94791],"7654669a":[()=>Promise.all([n.e(532),n.e(3459)]).then(n.bind(n,34260)),"@site/docs/howtos/solutions/fraud-detection/digital-identity-validation/index-digital-identity-validation.mdx",34260],78895142:[()=>Promise.all([n.e(532),n.e(7919)]).then(n.bind(n,22801)),"@site/docs/develop/rust/index-rust.mdx",22801],"7a1dcf5b":[()=>n.e(9572).then(n.bind(n,95149)),"@site/docs/develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index.md",95149],"7a460b64":[()=>Promise.all([n.e(532),n.e(7826)]).then(n.bind(n,93880)),"@site/docs/howtos/quick-start/cheat-sheets/sets.mdx",93880],"7f1e28a5":[()=>Promise.all([n.e(532),n.e(1727)]).then(n.bind(n,62872)),"@site/docs/howtos/herokujava/index-herokujava.mdx",62872],"7f823891":[()=>n.e(4931).then(n.bind(n,96098)),"@site/docs/howtos/solutions/real-time-inventory/common-rti/customer-proofs.mdx",96098],"8083ca96":[()=>n.e(3019).then(n.bind(n,86663)),"@site/docs/modules/redisjson/index-redisjson.mdx",86663],"81b2d599":[()=>Promise.all([n.e(532),n.e(3892)]).then(n.bind(n,74789)),"@site/docs/howtos/redisgraph/using-go/index-usinggo.mdx",74789],"81fab8ae":[()=>Promise.all([n.e(532),n.e(9605)]).then(n.bind(n,47041)),"@site/docs/develop/python/fastapi/index-fastapi.mdx",47041],"82b6bb4d":[()=>n.e(8345).then(n.bind(n,88868)),"@site/docs/create/aws/README.md",88868],"83a556d4":[()=>n.e(8145).then(n.bind(n,60088)),"@site/docs/modules/redisbloom/index-redisbloom.mdx",60088],"8460a6e0":[()=>Promise.all([n.e(532),n.e(8003)]).then(n.bind(n,46086)),"@site/docs/create/kubernetes/kubernetes-operator/index-kubernetes-operator.mdx",46086],"84711cce":[()=>Promise.all([n.e(532),n.e(6517)]).then(n.bind(n,85997)),"@site/docs/get-involved/redis-insiders/jyotsna-gupta/index-jyotsna-gupta.mdx",85997],"84ad0742":[()=>n.e(9047).then(n.bind(n,69986)),"@site/src/pages/lp/thank-you.tsx",69986],"85d526b8":[()=>Promise.all([n.e(532),n.e(1367)]).then(n.bind(n,46345)),"@site/docs/howtos/redisgraph/redisgraphmovies/index-redisgraphmovies.mdx",46345],"862d5cd0":[()=>n.e(6202).then(n.bind(n,43738)),"@site/docs/modules/redistimeseries/index-redistimeseries.mdx",43738],"8632c9a0":[()=>Promise.all([n.e(532),n.e(2451)]).then(n.bind(n,19001)),"@site/docs/operate/redis-at-scale/scalability/clustering-in-redis/index-scalability.mdx",19001],"8632df87":[()=>Promise.all([n.e(532),n.e(7813)]).then(n.bind(n,90203)),"@site/docs/develop/node/node-crash-course/whatisredis/index-whatisredis.mdx",90203],"872db8be":[()=>Promise.all([n.e(532),n.e(1309)]).then(n.bind(n,64500)),"@site/docs/howtos/quick-start/cheat-sheets/connect.mdx",64500],"879b2dca":[()=>Promise.all([n.e(532),n.e(4506)]).then(n.bind(n,28409)),"@site/docs/develop/node/node-crash-course/managingsuccess/index-managingsuccess.mdx",28409],"886ca5ea":[()=>n.e(1037).then(n.bind(n,7062)),"@site/docs/get-involved/hacktoberfest/lara-aasem-story/index-lara-aasem-story.mdx",7062],"88c087fa":[()=>Promise.all([n.e(532),n.e(9590)]).then(n.bind(n,15049)),"@site/docs/howtos/redisgraph/using-rust/index-usingrust.mdx",15049],"899fdd9f":[()=>n.e(1356).then(n.t.bind(n,83769,19)),"/home/runner/work/redis-developer.github.io/redis-developer.github.io/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",83769],"8d1d1c2e":[()=>n.e(7811).then(n.bind(n,81708)),"@site/docs/operate/redis-at-scale/observability/data-points-in-redis/index-data-points-in-redis.mdx",81708],"8ec5e180":[()=>Promise.all([n.e(532),n.e(6919)]).then(n.bind(n,43954)),"@site/docs/get-involved/devcember/index-devcember.mdx",43954],"8fea5263":[()=>n.e(7292).then(n.bind(n,8731)),"@site/docs/create/cloud/index-cloud.mdx",8731],"90e92e2d":[()=>Promise.all([n.e(532),n.e(7642)]).then(n.bind(n,1590)),"@site/docs/develop/node/redis-om/index-redis-om.mdx",1590],"92dce1fb":[()=>Promise.all([n.e(532),n.e(9884)]).then(n.bind(n,34730)),"@site/docs/howtos/quick-start/index-quick-start.mdx",34730],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],94686630:[()=>n.e(2925).then(n.bind(n,98781)),"@site/docs/operate/redis-at-scale/talking-to-redis/initial-tuning/index-initial-tuning.mdx",98781],"94f8b490":[()=>Promise.all([n.e(532),n.e(9045)]).then(n.bind(n,135)),"@site/docs/howtos/quick-start/cheat-sheets/streams.mdx",135],"95a8df98":[()=>n.e(9589).then(n.bind(n,4071)),"@site/docs/howtos/redisgraph/using-dotnet/index-usingdotnet.md",4071],"965be803":[()=>n.e(6657).then(n.bind(n,39149)),"@site/docs/develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries.md",39149],"96c61e5d":[()=>n.e(1617).then(n.bind(n,19950)),"@site/docs/develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filter.md",19950],"97a92876":[()=>Promise.all([n.e(532),n.e(2066)]).then(n.bind(n,62283)),"@site/docs/create/aws/bidding-on-aws/index-bidding-on-aws.mdx",62283],"9918870c":[()=>n.e(9184).then(n.bind(n,2588)),"@site/docs/create/aws/redis-on-aws/README.md",2588],"994c0519":[()=>Promise.all([n.e(532),n.e(3941),n.e(3659)]).then(n.bind(n,22141)),"@site/docs/explore/index-explore.mdx",22141],"99cb7080":[()=>Promise.all([n.e(532),n.e(1629)]).then(n.bind(n,80024)),"@site/docs/develop/ruby/index-ruby.mdx",80024],"9a2aa159":[()=>Promise.all([n.e(532),n.e(8681)]).then(n.bind(n,75002)),"@site/docs/develop/node/gettingstarted/index-gettingstarted.mdx",75002],"9a2b95c5":[()=>Promise.all([n.e(532),n.e(6170)]).then(n.bind(n,49841)),"@site/docs/create/aws/redis-on-aws/index-redis-on-aws.mdx",49841],"9c28af5e":[()=>Promise.all([n.e(532),n.e(3941),n.e(4802)]).then(n.bind(n,39206)),"@site/docs/develop/java/spring/index-spring.mdx",39206],"9d037edf":[()=>Promise.all([n.e(532),n.e(3941),n.e(9190)]).then(n.bind(n,7498)),"@site/docs/develop/java/index-java.mdx",7498],"9d845a85":[()=>n.e(3156).then(n.bind(n,81405)),"@site/docs/operate/redis-at-scale/high-availability/basic-replication/index-basic-replication.mdx",81405],"9d90cc60":[()=>Promise.all([n.e(532),n.e(134)]).then(n.bind(n,44427)),"@site/docs/create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis.mdx",44427],"9daaef4f":[()=>Promise.all([n.e(532),n.e(2341)]).then(n.bind(n,64640)),"@site/docs/howtos/solutions/fraud-detection/transaction-risk-scoring/index-transaction-risk-scoring.mdx",64640],"9e5bb348":[()=>Promise.all([n.e(532),n.e(6835)]).then(n.bind(n,65337)),"@site/docs/howtos/solutions/vector/getting-started-vector/index-getting-started-vector.mdx",65337],"9eeb107e":[()=>Promise.all([n.e(532),n.e(221)]).then(n.bind(n,41404)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_3/index-lesson_3.mdx",41404],"9f54a902":[()=>Promise.all([n.e(532),n.e(7269)]).then(n.bind(n,82749)),"@site/docs/howtos/quick-start/cheat-sheets/hashes.mdx",82749],"9f69dad8":[()=>n.e(5044).then(n.bind(n,86928)),"@site/docs/tutorials/redisearch/getting-started/index-redisearch-getting-started.mdx",86928],a3dbe69d:[()=>n.e(5928).then(n.bind(n,12962)),"@site/docs/operate/redis-at-scale/scalability/index-scalability.mdx",12962],a5b41932:[()=>Promise.all([n.e(532),n.e(5100)]).then(n.bind(n,87221)),"@site/docs/create/redis-functions/index-redis-functions.mdx",87221],a5c3d9e9:[()=>Promise.all([n.e(532),n.e(5683)]).then(n.bind(n,17871)),"@site/docs/operate/redis-at-scale/course-wrap-up/index-wrap-up.mdx",17871],a6e0ba43:[()=>n.e(9290).then(n.bind(n,34344)),"@site/docs/operate/redis-at-scale/scalability/redis-cli-with-redis-cluster/index-redis-cli-with-redis-cluster.mdx",34344],a8be125d:[()=>Promise.all([n.e(532),n.e(4821)]).then(n.bind(n,56439)),"@site/docs/howtos/ratelimiting/index-ratelimiting.mdx",56439],aa02f6e6:[()=>Promise.all([n.e(532),n.e(3721)]).then(n.bind(n,38160)),"@site/docs/howtos/redisgraph/using-redisinsight/index-usingredisinsight.mdx",38160],aa68f0e9:[()=>n.e(7367).then(n.bind(n,61804)),"@site/docs/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search.mdx",61804],ab704c68:[()=>Promise.all([n.e(532),n.e(9008)]).then(n.bind(n,94188)),"@site/docs/howtos/shoppingcart/index-shoppingcart.mdx",94188],ad08431a:[()=>Promise.all([n.e(532),n.e(2684)]).then(n.bind(n,45094)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_1/index-lesson_1.mdx",45094],af72bfd1:[()=>n.e(3007).then(n.bind(n,94047)),"@site/docs/howtos/solutions/caching-architecture/common-caching/caching-movie-app.mdx",94047],b0c5f580:[()=>n.e(3106).then(n.bind(n,39114)),"@site/docs/guides/indexing/indexing-querying.mdx",39114],b0c8cd2e:[()=>n.e(5853).then(n.bind(n,9885)),"@site/docs/operate/redis-at-scale/high-availability/understanding-sentinels/index-understanding-sentinels.mdx",9885],b2c8b850:[()=>n.e(5998).then(n.bind(n,87315)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-sku.mdx",87315],b3b34ca6:[()=>n.e(4479).then(n.bind(n,82349)),"@site/docs/howtos/solutions/real-time-inventory/available-to-promise/api/update-sku.mdx",82349],b3fefca0:[()=>Promise.all([n.e(532),n.e(5307)]).then(n.bind(n,31905)),"@site/docs/operate/orchestration/kubernetes-operator/index-kubernetes-operator.mdx",31905],b400c9cd:[()=>Promise.all([n.e(532),n.e(5290)]).then(n.bind(n,17954)),"@site/docs/explore/datadog/index-datadog.mdx",17954],b51fdc8c:[()=>Promise.all([n.e(532),n.e(1284)]).then(n.bind(n,224)),"@site/docs/create/azurefunctions/index-azurefunctions.mdx",224],b59188bc:[()=>n.e(8464).then(n.bind(n,6517)),"@site/docs/develop/dotnet/aspnetcore/rate-limiting/sliding-window/index-sliding-rate-limiter.md",6517],b697db3c:[()=>Promise.all([n.e(532),n.e(8563)]).then(n.bind(n,85615)),"@site/docs/operate/observability/datadog/index-datadog.mdx",85615],b70c40d3:[()=>Promise.all([n.e(532),n.e(9353)]).then(n.bind(n,62307)),"@site/docs/develop/node/node-crash-course/sampleapplicationoverview/index-sampleapplicationoverview.mdx",62307],b88966c9:[()=>Promise.all([n.e(532),n.e(3165)]).then(n.bind(n,6134)),"@site/docs/develop/java/spring/rate-limiting/getting-started/getting-started.mdx",6134],b8f4daa2:[()=>Promise.all([n.e(532),n.e(3814)]).then(n.bind(n,46672)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_6/index-lesson_6.mdx",46672],b949b843:[()=>n.e(2930).then(n.bind(n,25391)),"@site/docs/operate/redis-at-scale/observability/index-observability.mdx",25391],ba498387:[()=>n.e(7676).then(n.bind(n,9146)),"@site/docs/howtos/moviesdatabase/query/index-query.mdx",9146],ba6f6003:[()=>Promise.all([n.e(532),n.e(4328)]).then(n.bind(n,94537)),"@site/docs/create/jenkins/index-jenkins.mdx",94537],bbaff741:[()=>Promise.all([n.e(532),n.e(3941),n.e(559)]).then(n.bind(n,62598)),"@site/docs/guides/index.mdx",62598],bbc4d579:[()=>n.e(4102).then(n.bind(n,92436)),"@site/docs/howtos/index-modules.mdx",92436],bc14dfd3:[()=>n.e(7644).then(n.bind(n,34045)),"@site/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis.mdx",34045],bda60f59:[()=>n.e(7880).then(n.bind(n,6818)),"@site/docs/operate/redis-at-scale/scalability/redis-cluster-and-client-libraries/index-redis-cluster-and-client-libraries.mdx",6818],bf9dc990:[()=>Promise.all([n.e(532),n.e(550)]).then(n.bind(n,31525)),"@site/docs/create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud.mdx",31525],bfe77eb6:[()=>n.e(7615).then(n.bind(n,83767)),"@site/docs/get-involved/discord/index-discord.mdx",83767],c1ab566a:[()=>Promise.all([n.e(532),n.e(459)]).then(n.bind(n,10128)),"@site/docs/develop/java/spring/redis-and-spring-course/lesson_5/index-lesson_5.mdx",10128],c1bb9856:[()=>Promise.all([n.e(532),n.e(5980)]).then(n.bind(n,46203)),"@site/docs/howtos/redisgraph/using-ruby/index-usingruby.mdx",46203],c1e8360a:[()=>n.e(3752).then(n.bind(n,34355)),"@site/docs/operate/orchestration/docker/images/README.md",34355],c2cefeac:[()=>Promise.all([n.e(532),n.e(1924)]).then(n.bind(n,70057)),"@site/docs/howtos/bert-qa-benchmarking/index-bert-qa-benchmarking-with-redisai-and-redisgears.mdx",70057],c3151dc9:[()=>n.e(1396).then(n.t.bind(n,15745,19)),"/home/runner/work/redis-developer.github.io/redis-developer.github.io/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",15745],c32ed07a:[()=>n.e(1056).then(n.bind(n,18392)),"@site/docs/howtos/solutions/real-time-inventory/common-rti/rti-challenges.mdx",18392],c3e7abab:[()=>n.e(8712).then(n.bind(n,51802)),"@site/src/pages/lp/learn-and-earn-jwt.tsx",51802],c414f47b:[()=>Promise.all([n.e(532),n.e(5500)]).then(n.bind(n,52875)),"@site/docs/create/windows/index-windows.mdx",52875],c42ebdb1:[()=>n.e(8562).then(n.bind(n,44094)),"@site/docs/howtos/solutions/real-time-inventory/common-rti/source-code-tip.mdx",44094],c551111a:[()=>Promise.all([n.e(532),n.e(3878)]).then(n.bind(n,53742)),"@site/docs/howtos/quick-start/cheat-sheets/generic.mdx",53742],c5c6e5e3:[()=>Promise.all([n.e(532),n.e(6470)]).then(n.bind(n,78824)),"@site/docs/howtos/solutions/microservices/api-gateway-caching/index-api-gateway-caching.mdx",78824],c65a5e23:[()=>n.e(1743).then(n.bind(n,13659)),"@site/docs/develop/dotnet/streams/streams-basics.md",13659],c98631ab:[()=>Promise.all([n.e(532),n.e(2536)]).then(n.bind(n,13287)),"@site/docs/howtos/nlp/index-nlp.mdx",13287],cb3ee170:[()=>n.e(8962).then(n.bind(n,72716)),"@site/docs/howtos/solutions/caching-architecture/common-caching/write-behind-vs-write-through.mdx",72716],ccdc297e:[()=>Promise.all([n.e(532),n.e(6082)]).then(n.bind(n,92417)),"@site/docs/develop/C/index-c.mdx",92417],cd548de4:[()=>Promise.all([n.e(532),n.e(7599)]).then(n.bind(n,16839)),"@site/docs/howtos/solutions/mobile-banking/account-dashboard/index-account-dashboard.mdx",16839],cefa0e41:[()=>n.e(1067).then(n.bind(n,8138)),"@site/docs/get-involved/redis-live/index-redis-live.mdx",8138],d119b4b9:[()=>n.e(3171).then(n.bind(n,36803)),"@site/docs/howtos/moviesdatabase/manage/index.manage.mdx",36803],d329623b:[()=>Promise.all([n.e(532),n.e(3941),n.e(4015)]).then(n.bind(n,28358)),"@site/docs/develop/java/spring/redis-om/index-redis-om-spring.mdx",28358],d3555a77:[()=>n.e(5805).then(n.bind(n,13055)),"@site/docs/operate/redis-at-scale/persistence-and-durability/introduction/index-introduction.mdx",13055],d3f14484:[()=>n.e(1966).then(n.bind(n,92148)),"@site/docs/howtos/solutions/mobile-banking/common-mb/additional-resources.mdx",92148],d5484ed9:[()=>n.e(9355).then(n.t.bind(n,6827,19)),"~docs/default/tag-tags-community-74e.json",6827],d63023de:[()=>Promise.all([n.e(532),n.e(4845)]).then(n.bind(n,12464)),"@site/docs/develop/java/spring/rate-limiting/fixed-window/index-fixed-window-reactive.mdx",12464],d661e85d:[()=>Promise.all([n.e(532),n.e(342)]).then(n.bind(n,3738)),"@site/docs/howtos/solutions/mobile-banking/session-management/index-session-management.mdx",3738],d69fc27c:[()=>n.e(8252).then(n.bind(n,86599)),"@site/docs/modules/redisgraph/index-redisgraph.mdx",86599],d7f02a39:[()=>n.e(6045).then(n.bind(n,71673)),"@site/docs/howtos/solutions/microservices/common-data/redis-enterprise.mdx",71673],d866cdfa:[()=>Promise.all([n.e(532),n.e(5745)]).then(n.bind(n,81789)),"@site/docs/create/aws/analytics-using-aws/index-analytics-using-aws.mdx",81789],d888d60e:[()=>Promise.all([n.e(532),n.e(3941),n.e(2206)]).then(n.bind(n,19089)),"@site/docs/develop/index-develop.mdx",19089],d9a0a71f:[()=>n.e(7678).then(n.bind(n,30768)),"@site/docs/develop/dotnet/aspnetcore/caching/basic/index-basic-api-caching.md",30768],d9fa573c:[()=>n.e(7530).then(n.bind(n,2290)),"@site/docs/modules/redisgears/index-redisgears.mdx",2290],db1d58d4:[()=>Promise.all([n.e(532),n.e(1348)]).then(n.bind(n,54040)),"@site/docs/develop/node/node-crash-course/introducingredisinsight/index-introducingredisinsight.mdx",54040],dc17824a:[()=>n.e(8255).then(n.bind(n,55426)),"@site/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip-old.mdx",55426],dc77741e:[()=>Promise.all([n.e(532),n.e(1234)]).then(n.bind(n,35188)),"@site/docs/howtos/solutions/vector/gen-ai-chatbot/index-gen-ai-chatbot.mdx",35188],ddd418a4:[()=>Promise.all([n.e(532),n.e(7729)]).then(n.bind(n,53188)),"@site/docs/howtos/quick-start/cheat-sheets/sorted-sets.mdx",53188],df203c0f:[()=>n.e(9924).then(n.bind(n,97068)),"@theme/DocTagDocListPage",97068],df84b43c:[()=>n.e(2970).then(n.bind(n,34795)),"@site/docs/howtos/solutions/fraud-detection/common-fraud/source-code-tip.mdx",34795],e133680b:[()=>Promise.all([n.e(532),n.e(153)]).then(n.bind(n,90363)),"@site/docs/operate/observability/redisdatasource/index-redisdatasource.mdx",90363],e14e08fc:[()=>n.e(2124).then(n.bind(n,56391)),"@site/docs/howtos/solutions/mobile-banking/common-mb/source-code-tip.mdx",56391],e1610694:[()=>n.e(4361).then(n.bind(n,51789)),"@site/docs/operate/redis-at-scale/talking-to-redis/redis-clients/index-redis-clients.mdx",51789],e1a3fa89:[()=>n.e(9566).then(n.bind(n,65628)),"@site/docs/operate/redis-at-scale/high-availability/exercise-1/index-exercise-1.mdx",65628],e1c2ddaa:[()=>n.e(3723).then(n.bind(n,90560)),"@site/docs/operate/redis-at-scale/observability/identifying-issues/index-identifying-issues.mdx",90560],e1d45d33:[()=>Promise.all([n.e(532),n.e(5658)]).then(n.bind(n,26111)),"@site/docs/operate/redis-at-scale/index-redis-at-scale.mdx",26111],e368a9fb:[()=>Promise.all([n.e(532),n.e(3941),n.e(9688)]).then(n.bind(n,21524)),"@site/docs/howtos/redisgraph/index-redisgraph.mdx",21524],e49a9233:[()=>Promise.all([n.e(532),n.e(6980)]).then(n.bind(n,33965)),"@site/docs/guides/security/how-to-use-tls-with-redis-enterprise/how-to-use-ssl-tls-with-redis-enterprise.mdx",33965],e65f8228:[()=>Promise.all([n.e(532),n.e(4230)]).then(n.bind(n,37114)),"@site/docs/develop/deno/index-deno.mdx",37114],e7e99a29:[()=>n.e(1701).then(n.bind(n,89748)),"@site/docs/operate/redis-at-scale/high-availability/introduction/index-index-introduction.mdx",89748],e7f62945:[()=>Promise.all([n.e(532),n.e(3941),n.e(5037)]).then(n.bind(n,90961)),"@site/docs/develop/node/node-crash-course/index-node-crash-course.mdx",90961],e83211e5:[()=>Promise.all([n.e(532),n.e(6584)]).then(n.bind(n,56591)),"@site/docs/howtos/hackernews/index-hackernews.mdx",56591],e8e1f04a:[()=>Promise.all([n.e(532),n.e(5050)]).then(n.bind(n,31486)),"@site/docs/howtos/redisgraph/using-javascript/index-usingjavascript.mdx",31486],e9b9d3de:[()=>n.e(3743).then(n.bind(n,52352)),"@site/docs/guides/security/index-security.mdx",52352],eaf6f8ac:[()=>Promise.all([n.e(532),n.e(9627)]).then(n.bind(n,76119)),"@site/docs/develop/node/node-crash-course/redisandnodejs/index-redisandnodejs.mdx",76119],eaf8982a:[()=>Promise.all([n.e(532),n.e(6487)]).then(n.bind(n,6926)),"@site/docs/develop/php/index-php.mdx",6926],eb92c419:[()=>n.e(7128).then(n.bind(n,92558)),"@site/docs/develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries.md",92558],ed35ad37:[()=>Promise.all([n.e(532),n.e(7894)]).then(n.bind(n,10042)),"@site/docs/howtos/solutions/microservices/cqrs/index-cqrs.mdx",10042],eed077d2:[()=>Promise.all([n.e(532),n.e(6023)]).then(n.bind(n,98090)),"@site/docs/operate/orchestration/docker/index-docker.mdx",98090],f1811081:[()=>Promise.all([n.e(532),n.e(3789)]).then(n.bind(n,10163)),"@site/docs/howtos/analytics/index-analytics.mdx",10163],f19dd2c1:[()=>Promise.all([n.e(532),n.e(3335)]).then(n.bind(n,54322)),"@site/docs/develop/dotnet/aspnetcore/rate-limiting/fixed-window/fixed-window.mdx",54322],f23cc535:[()=>Promise.all([n.e(532),n.e(3820)]).then(n.bind(n,84078)),"@site/docs/howtos/quick-start/cheat-sheets/cheat-sheet.mdx",84078],f242a466:[()=>n.e(2250).then(n.bind(n,33756)),"@site/docs/operate/redis-at-scale/talking-to-redis/command-line-tool/index-command-line-tool.mdx",33756],f251a97b:[()=>Promise.all([n.e(532),n.e(8477)]).then(n.bind(n,24701)),"@site/docs/create/aws/slackbot/index-slackbot.mdx",24701],f2d3ddf1:[()=>Promise.all([n.e(532),n.e(8643)]).then(n.bind(n,39574)),"@site/docs/develop/node/node-crash-course/caching/index-caching.mdx",39574],f3dbe95e:[()=>Promise.all([n.e(532),n.e(9012)]).then(n.bind(n,8714)),"@site/docs/howtos/redisgraph/using-python/index-usingpython.mdx",8714],f4457846:[()=>Promise.all([n.e(532),n.e(9769)]).then(n.bind(n,30464)),"@site/docs/develop/node/node-crash-course/domainobjectswithhashes/index-domainobjectswithhashes.mdx",30464],f5985471:[()=>n.e(1849).then(n.bind(n,87269)),"@site/docs/howtos/solutions/caching-architecture/common-caching/source-code-movie-app.mdx",87269],f7282e3d:[()=>n.e(8560).then(n.bind(n,78055)),"@site/docs/howtos/security/tls.mdx",78055],f88d2135:[()=>n.e(116).then(n.bind(n,86525)),"@site/docs/operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis/index-persistence-options-in-redis.mdx",86525],f8bde386:[()=>n.e(2115).then(n.bind(n,56320)),"@site/docs/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects.md",56320],f8c0f22b:[()=>Promise.all([n.e(532),n.e(2649)]).then(n.bind(n,25330)),"@site/docs/develop/node/node-crash-course/checkinswithstreams/index-checkinswithstreams.mdx",25330],f9ed4a2e:[()=>n.e(8454).then(n.bind(n,4975)),"@site/docs/howtos/solutions/microservices/common-data/microservices-ecommerce.mdx",4975],fb01d865:[()=>Promise.all([n.e(532),n.e(3941),n.e(3375)]).then(n.bind(n,94603)),"@site/docs/operate/orchestration/index-orchestration.mdx",94603],fba0c1ab:[()=>n.e(5550).then(n.bind(n,16265)),"@site/docs/create/cloud/rediscloud/index-recloud.mdx",16265],fd091685:[()=>n.e(7682).then(n.bind(n,48023)),"@site/docs/howtos/moviesdatabase/querymovies/index-querymovies.mdx",48023],fd0bff62:[()=>Promise.all([n.e(532),n.e(2218)]).then(n.bind(n,97836)),"@site/docs/get-involved/redis-insiders/michael-owolabi/index-michael-owolabi.mdx",97836],fd375cb3:[()=>n.e(7119).then(n.bind(n,6055)),"@site/docs/modules/redisearch/index-redisearch.mdx",6055],fe9a220a:[()=>Promise.all([n.e(532),n.e(3984)]).then(n.bind(n,85144)),"@site/docs/create/openshift/index-openshift.mdx",85144]};function l(e){let{error:t,retry:n,pastDelay:o}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):o?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var d=n(99670),u=n(30226);function p(e,t){if("*"===e)return i()({loading:l,loader:()=>Promise.all([n.e(3614),n.e(486)]).then(n.bind(n,20486)),modules:["@theme/NotFound"],webpack:()=>[20486],render(e,t){const n=e.default;return r.createElement(u.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const a=s[`${e}-${t}`],p={},h=[],m=[],f=(0,d.Z)(a);return Object.entries(f).forEach((e=>{let[t,n]=e;const r=c[n];r&&(p[t]=r[0],h.push(r[1]),m.push(r[2]))})),i().Map({loading:l,loader:p,modules:h,webpack:()=>m,render(t,n){const i=JSON.parse(JSON.stringify(a));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let a=i;const s=n.split(".");s.slice(0,-1).forEach((e=>{a=a[e]})),a[s[s.length-1]]=o}));const s=i.__comp;delete i.__comp;const c=i.__context;return delete i.__context,r.createElement(u.z,{value:c},r.createElement(s,(0,o.Z)({},i,n)))}})}const h=[{path:"/lp/learn-and-earn-jwt",component:p("/lp/learn-and-earn-jwt","b98"),exact:!0},{path:"/lp/thank-you",component:p("/lp/thank-you","363"),exact:!0},{path:"/tags",component:p("/tags","87a"),exact:!0},{path:"/tags/community",component:p("/tags/community","ede"),exact:!0},{path:"/",component:p("/","c0a"),exact:!0},{path:"/",component:p("/","224"),routes:[{path:"/community/",component:p("/community/","8f6"),exact:!0,sidebar:"docs"},{path:"/community/discord/",component:p("/community/discord/","d9c"),exact:!0,sidebar:"docs"},{path:"/create",component:p("/create","adf"),exact:!0,sidebar:"docs"},{path:"/create/aws",component:p("/create/aws","f89"),exact:!0,sidebar:"docs"},{path:"/create/aws/",component:p("/create/aws/","9a5"),exact:!0},{path:"/create/aws/analytics-using-aws",component:p("/create/aws/analytics-using-aws","7cb"),exact:!0,sidebar:"docs"},{path:"/create/aws/bidding-on-aws",component:p("/create/aws/bidding-on-aws","4a2"),exact:!0,sidebar:"docs"},{path:"/create/aws/chatapp",component:p("/create/aws/chatapp","4fd"),exact:!0,sidebar:"docs"},{path:"/create/aws/import/database-migration-aws-elasticache-redis-enterprise-cloud/",component:p("/create/aws/import/database-migration-aws-elasticache-redis-enterprise-cloud/","06d"),exact:!0,sidebar:"docs"},{path:"/create/aws/redis-on-aws",component:p("/create/aws/redis-on-aws","f46"),exact:!0,sidebar:"docs"},{path:"/create/aws/redis-on-aws/",component:p("/create/aws/redis-on-aws/","956"),exact:!0},{path:"/create/aws/redis-on-aws/images/",component:p("/create/aws/redis-on-aws/images/","935"),exact:!0},{path:"/create/aws/slackbot",component:p("/create/aws/slackbot","6cc"),exact:!0,sidebar:"docs"},{path:"/create/aws/terraform",component:p("/create/aws/terraform","e99"),exact:!0,sidebar:"docs"},{path:"/create/azure",component:p("/create/azure","3d9"),exact:!0,sidebar:"docs"},{path:"/create/azure/portal",component:p("/create/azure/portal","b4d"),exact:!0,sidebar:"docs"},{path:"/create/azurefunctions",component:p("/create/azurefunctions","d41"),exact:!0,sidebar:"docs"},{path:"/create/cloud/",component:p("/create/cloud/","a22"),exact:!0},{path:"/create/cloud/aws",component:p("/create/cloud/aws","1f6"),exact:!0},{path:"/create/cloud/azure",component:p("/create/cloud/azure","f62"),exact:!0},{path:"/create/cloud/gcp",component:p("/create/cloud/gcp","66f"),exact:!0},{path:"/create/cloud/images/",component:p("/create/cloud/images/","30e"),exact:!0},{path:"/create/cloud/rediscloud",component:p("/create/cloud/rediscloud","f4e"),exact:!0},{path:"/create/cloud/rediscloud/images/",component:p("/create/cloud/rediscloud/images/","03a"),exact:!0},{path:"/create/docker/",component:p("/create/docker/","922"),exact:!0,sidebar:"docs"},{path:"/create/docker/nodejs-nginx-redis",component:p("/create/docker/nodejs-nginx-redis","71c"),exact:!0,sidebar:"docs"},{path:"/create/heroku",component:p("/create/heroku","132"),exact:!0},{path:"/create/heroku/portal",component:p("/create/heroku/portal","c3d"),exact:!0},{path:"/create/images/",component:p("/create/images/","e35"),exact:!0},{path:"/create/jenkins",component:p("/create/jenkins","ab5"),exact:!0,sidebar:"docs"},{path:"/create/kubernetes/",component:p("/create/kubernetes/","a67"),exact:!0,sidebar:"docs"},{path:"/create/kubernetes/kubernetes-operator",component:p("/create/kubernetes/kubernetes-operator","90d"),exact:!0},{path:"/create/openshift",component:p("/create/openshift","a5d"),exact:!0},{path:"/create/redis-functions",component:p("/create/redis-functions","e49"),exact:!0,sidebar:"docs"},{path:"/create/windows",component:p("/create/windows","a2c"),exact:!0,sidebar:"docs"},{path:"/devcember/",component:p("/devcember/","cb8"),exact:!0,sidebar:"docs"},{path:"/develop",component:p("/develop","286"),exact:!0,sidebar:"docs"},{path:"/develop/C/",component:p("/develop/C/","9fc"),exact:!0,sidebar:"docs"},{path:"/develop/deno/",component:p("/develop/deno/","231"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet",component:p("/develop/dotnet","53a"),exact:!0},{path:"/develop/dotnet/aspnetcore/caching/basic-api-caching",component:p("/develop/dotnet/aspnetcore/caching/basic-api-caching","a9c"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/aspnetcore/rate-limiting/fixed-window",component:p("/develop/dotnet/aspnetcore/rate-limiting/fixed-window","794"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/aspnetcore/rate-limiting/middleware",component:p("/develop/dotnet/aspnetcore/rate-limiting/middleware","db7"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/aspnetcore/rate-limiting/sliding-window",component:p("/develop/dotnet/aspnetcore/rate-limiting/sliding-window","e2f"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects",component:p("/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects","ff5"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/aggregations",component:p("/develop/dotnet/redis-om-dotnet/aggregations","574"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/aggregations/apply-functions",component:p("/develop/dotnet/redis-om-dotnet/aggregations/apply-functions","516"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/aggregations/groups/groups",component:p("/develop/dotnet/redis-om-dotnet/aggregations/groups/groups","250"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/searching/creating-an-index",component:p("/develop/dotnet/redis-om-dotnet/searching/creating-an-index","7af"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/searching/geo-filters",component:p("/develop/dotnet/redis-om-dotnet/searching/geo-filters","8f9"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/searching/numeric-queries",component:p("/develop/dotnet/redis-om-dotnet/searching/numeric-queries","ddd"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/redis-om-dotnet/simple-text-queries",component:p("/develop/dotnet/redis-om-dotnet/simple-text-queries","842"),exact:!0,sidebar:"docs"},{path:"/develop/dotnet/streams/stream-basics",component:p("/develop/dotnet/streams/stream-basics","968"),exact:!0,sidebar:"docs"},{path:"/develop/guides/netlify/getting-started",component:p("/develop/guides/netlify/getting-started","59b"),exact:!0},{path:"/develop/java",component:p("/develop/java","209"),exact:!0,sidebar:"docs"},{path:"/develop/java/getting-started",component:p("/develop/java/getting-started","726"),exact:!0},{path:"/develop/java/redis-and-spring-course",component:p("/develop/java/redis-and-spring-course","320"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_1",component:p("/develop/java/redis-and-spring-course/lesson_1","d73"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_2",component:p("/develop/java/redis-and-spring-course/lesson_2","344"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_3",component:p("/develop/java/redis-and-spring-course/lesson_3","8c6"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_4",component:p("/develop/java/redis-and-spring-course/lesson_4","66c"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_5",component:p("/develop/java/redis-and-spring-course/lesson_5","fe3"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_6",component:p("/develop/java/redis-and-spring-course/lesson_6","099"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_7",component:p("/develop/java/redis-and-spring-course/lesson_7","693"),exact:!0,sidebar:"docs"},{path:"/develop/java/redis-and-spring-course/lesson_9",component:p("/develop/java/redis-and-spring-course/lesson_9","afa"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring",component:p("/develop/java/spring","32d"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/",component:p("/develop/java/spring/","53f"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/rate-limiting",component:p("/develop/java/spring/rate-limiting","1b6"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/rate-limiting/fixed-window",component:p("/develop/java/spring/rate-limiting/fixed-window","718"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/rate-limiting/fixed-window/reactive",component:p("/develop/java/spring/rate-limiting/fixed-window/reactive","370"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/rate-limiting/fixed-window/reactive-gears",component:p("/develop/java/spring/rate-limiting/fixed-window/reactive-gears","676"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/rate-limiting/fixed-window/reactive-lua",component:p("/develop/java/spring/rate-limiting/fixed-window/reactive-lua","40f"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/rate-limiting/getting-started",component:p("/develop/java/spring/rate-limiting/getting-started","77d"),exact:!0},{path:"/develop/java/spring/redis-om/redis-om-spring",component:p("/develop/java/spring/redis-om/redis-om-spring","a5e"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/redis-om/redis-om-spring-hash",component:p("/develop/java/spring/redis-om/redis-om-spring-hash","dc6"),exact:!0,sidebar:"docs"},{path:"/develop/java/spring/redis-om/redis-om-spring-json",component:p("/develop/java/spring/redis-om/redis-om-spring-json","649"),exact:!0,sidebar:"docs"},{path:"/develop/node",component:p("/develop/node","f3f"),exact:!0,sidebar:"docs"},{path:"/develop/node/gettingstarted",component:p("/develop/node/gettingstarted","558"),exact:!0,sidebar:"docs"},{path:"/develop/node/node-crash-course",component:p("/develop/node/node-crash-course","c2f"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/advancedstreams",component:p("/develop/node/nodecrashcourse/advancedstreams","cf2"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/caching",component:p("/develop/node/nodecrashcourse/caching","7d1"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/checkinswithstreams",component:p("/develop/node/nodecrashcourse/checkinswithstreams","872"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/coursewrapup",component:p("/develop/node/nodecrashcourse/coursewrapup","520"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/domainobjectswithhashes",component:p("/develop/node/nodecrashcourse/domainobjectswithhashes","1ba"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/introducingredisinsight",component:p("/develop/node/nodecrashcourse/introducingredisinsight","6e9"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/introductiontomodules",component:p("/develop/node/nodecrashcourse/introductiontomodules","d30"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/managingsuccess",component:p("/develop/node/nodecrashcourse/managingsuccess","97b"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/redisandnodejs",component:p("/develop/node/nodecrashcourse/redisandnodejs","304"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/redisbloom",component:p("/develop/node/nodecrashcourse/redisbloom","47a"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/redisearch",component:p("/develop/node/nodecrashcourse/redisearch","495"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/redisjson",component:p("/develop/node/nodecrashcourse/redisjson","010"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/runningtheapplication",component:p("/develop/node/nodecrashcourse/runningtheapplication","fc8"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/sampleapplicationoverview",component:p("/develop/node/nodecrashcourse/sampleapplicationoverview","7a7"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/sessionstorage",component:p("/develop/node/nodecrashcourse/sessionstorage","e0e"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/welcome",component:p("/develop/node/nodecrashcourse/welcome","95d"),exact:!0,sidebar:"docs"},{path:"/develop/node/nodecrashcourse/whatisredis",component:p("/develop/node/nodecrashcourse/whatisredis","84c"),exact:!0,sidebar:"docs"},{path:"/develop/node/redis-om",component:p("/develop/node/redis-om","29c"),exact:!0,sidebar:"docs"},{path:"/develop/php/",component:p("/develop/php/","c29"),exact:!0,sidebar:"docs"},{path:"/develop/python/fastapi",component:p("/develop/python/fastapi","084"),exact:!0,sidebar:"docs"},{path:"/develop/python/redis-om",component:p("/develop/python/redis-om","b88"),exact:!0},{path:"/develop/ruby/",component:p("/develop/ruby/","b52"),exact:!0,sidebar:"docs"},{path:"/develop/rust/",component:p("/develop/rust/","efc"),exact:!0},{path:"/ebooks/8-nosql-data-modeling-patterns",component:p("/ebooks/8-nosql-data-modeling-patterns","16d"),exact:!0,sidebar:"docs"},{path:"/ebooks/three-caching-design-patterns",component:p("/ebooks/three-caching-design-patterns","263"),exact:!0,sidebar:"docs"},{path:"/explore",component:p("/explore","1a7"),exact:!0,sidebar:"docs"},{path:"/explore/datadog",component:p("/explore/datadog","c2d"),exact:!0,sidebar:"docs"},{path:"/explore/import/",component:p("/explore/import/","30d"),exact:!0,sidebar:"docs"},{path:"/explore/redisdatasource",component:p("/explore/redisdatasource","057"),exact:!0,sidebar:"docs"},{path:"/explore/riot",component:p("/explore/riot","e2d"),exact:!0,sidebar:"docs"},{path:"/guide/security/how-to-use-ssl-tls-with-redis-enterprise/",component:p("/guide/security/how-to-use-ssl-tls-with-redis-enterprise/","908"),exact:!0},{path:"/guides/",component:p("/guides/","7b8"),exact:!0},{path:"/guides/data-modeling/",component:p("/guides/data-modeling/","32f"),exact:!0},{path:"/guides/import-data/",component:p("/guides/import-data/","59b"),exact:!0},{path:"/guides/import/",component:p("/guides/import/","292"),exact:!0},{path:"/guides/import/database-migration-aws-elasticache-redis-enterprise-cloud/",component:p("/guides/import/database-migration-aws-elasticache-redis-enterprise-cloud/","72c"),exact:!0},{path:"/guides/indexing/",component:p("/guides/indexing/","7d1"),exact:!0},{path:"/guides/security/",component:p("/guides/security/","c42"),exact:!0},{path:"/hacktoberfest/",component:p("/hacktoberfest/","0a3"),exact:!0,sidebar:"docs"},{path:"/hacktoberfest/stories/lara-aasem",component:p("/hacktoberfest/stories/lara-aasem","c0f"),exact:!0,sidebar:"docs"},{path:"/hacktoberfest/stories/vincent-aceto",component:p("/hacktoberfest/stories/vincent-aceto","cdb"),exact:!0,sidebar:"docs"},{path:"/howtos/analytics",component:p("/howtos/analytics","c58"),exact:!0,sidebar:"docs"},{path:"/howtos/antipatterns/",component:p("/howtos/antipatterns/","5e4"),exact:!0,sidebar:"docs"},{path:"/howtos/caching",component:p("/howtos/caching","976"),exact:!0,sidebar:"docs"},{path:"/howtos/chatapp",component:p("/howtos/chatapp","a4d"),exact:!0,sidebar:"docs"},{path:"/howtos/frauddetection",component:p("/howtos/frauddetection","eb3"),exact:!0,sidebar:"docs"},{path:"/howtos/hackernews",component:p("/howtos/hackernews","efd"),exact:!0,sidebar:"docs"},{path:"/howtos/herokujava",component:p("/howtos/herokujava","009"),exact:!0,sidebar:"docs"},{path:"/howtos/herokunodejs",component:p("/howtos/herokunodejs","91a"),exact:!0,sidebar:"docs"},{path:"/howtos/herokupython",component:p("/howtos/herokupython","4ff"),exact:!0,sidebar:"docs"},{path:"/howtos/index-modules",component:p("/howtos/index-modules","3e9"),exact:!0},{path:"/howtos/leaderboard",component:p("/howtos/leaderboard","805"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase",component:p("/howtos/moviesdatabase","20c"),exact:!0},{path:"/howtos/moviesdatabase/advancedoption",component:p("/howtos/moviesdatabase/advancedoption","318"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/aggregation",component:p("/howtos/moviesdatabase/aggregation","5ef"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/create",component:p("/howtos/moviesdatabase/create","b0c"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/import",component:p("/howtos/moviesdatabase/import","e9c"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/install",component:p("/howtos/moviesdatabase/install","a45"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/manage",component:p("/howtos/moviesdatabase/manage","ce6"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/query",component:p("/howtos/moviesdatabase/query","020"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/querymovies",component:p("/howtos/moviesdatabase/querymovies","4e4"),exact:!0,sidebar:"docs"},{path:"/howtos/moviesdatabase/sampleapp",component:p("/howtos/moviesdatabase/sampleapp","cf3"),exact:!0,sidebar:"docs"},{path:"/howtos/nlp",component:p("/howtos/nlp","20b"),exact:!0,sidebar:"docs"},{path:"/howtos/popupstore",component:p("/howtos/popupstore","44e"),exact:!0,sidebar:"docs"},{path:"/howtos/quick-start",component:p("/howtos/quick-start","97e"),exact:!0,sidebar:"docs"},{path:"/howtos/quick-start/cheat-sheet",component:p("/howtos/quick-start/cheat-sheet","74e"),exact:!0,sidebar:"docs"},{path:"/howtos/quick-start/cheat-sheets/connect",component:p("/howtos/quick-start/cheat-sheets/connect","6ed"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/generic",component:p("/howtos/quick-start/cheat-sheets/generic","ae1"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/hashes",component:p("/howtos/quick-start/cheat-sheets/hashes","272"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/json",component:p("/howtos/quick-start/cheat-sheets/json","8ba"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/lists",component:p("/howtos/quick-start/cheat-sheets/lists","36c"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/search-and-query",component:p("/howtos/quick-start/cheat-sheets/search-and-query","da6"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/sets",component:p("/howtos/quick-start/cheat-sheets/sets","17d"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/sorted-sets",component:p("/howtos/quick-start/cheat-sheets/sorted-sets","e8d"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/streams",component:p("/howtos/quick-start/cheat-sheets/streams","5e6"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/strings",component:p("/howtos/quick-start/cheat-sheets/strings","024"),exact:!0},{path:"/howtos/quick-start/cheat-sheets/triggers-and-functions",component:p("/howtos/quick-start/cheat-sheets/triggers-and-functions","36a"),exact:!0},{path:"/howtos/ratelimiting",component:p("/howtos/ratelimiting","115"),exact:!0,sidebar:"docs"},{path:"/howtos/redisai/bert-qa-benchmarking-with-redisai-and-redisgears",component:p("/howtos/redisai/bert-qa-benchmarking-with-redisai-and-redisgears","f44"),exact:!0,sidebar:"docs"},{path:"/howtos/redisgraph/",component:p("/howtos/redisgraph/","869"),exact:!0},{path:"/howtos/redisgraph/csvtograph",component:p("/howtos/redisgraph/csvtograph","6e1"),exact:!0},{path:"/howtos/redisgraph/explore-python-code",component:p("/howtos/redisgraph/explore-python-code","86f"),exact:!0},{path:"/howtos/redisgraph/getting-started",component:p("/howtos/redisgraph/getting-started","5f7"),exact:!0},{path:"/howtos/redisgraph/redisgraph-cheatsheet",component:p("/howtos/redisgraph/redisgraph-cheatsheet","b9c"),exact:!0},{path:"/howtos/redisgraph/redisgraphmovies",component:p("/howtos/redisgraph/redisgraphmovies","790"),exact:!0},{path:"/howtos/redisgraph/using-dotnet",component:p("/howtos/redisgraph/using-dotnet","002"),exact:!0},{path:"/howtos/redisgraph/using-go",component:p("/howtos/redisgraph/using-go","6dc"),exact:!0},{path:"/howtos/redisgraph/using-javascript",component:p("/howtos/redisgraph/using-javascript","f70"),exact:!0},{path:"/howtos/redisgraph/using-python",component:p("/howtos/redisgraph/using-python","4a9"),exact:!0},{path:"/howtos/redisgraph/using-redisinsight",component:p("/howtos/redisgraph/using-redisinsight","85b"),exact:!0},{path:"/howtos/redisgraph/using-ruby",component:p("/howtos/redisgraph/using-ruby","797"),exact:!0},{path:"/howtos/redisgraph/using-rust",component:p("/howtos/redisgraph/using-rust","ed5"),exact:!0},{path:"/howtos/security/",component:p("/howtos/security/","602"),exact:!0,sidebar:"docs"},{path:"/howtos/shoppingcart",component:p("/howtos/shoppingcart","cc7"),exact:!0},{path:"/howtos/socialnetwork/",component:p("/howtos/socialnetwork/","7c9"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions",component:p("/howtos/solutions","d37"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/caching-architecture/cache-prefetching",component:p("/howtos/solutions/caching-architecture/cache-prefetching","7ad"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/caching-architecture/common-caching/caching-movie-app",component:p("/howtos/solutions/caching-architecture/common-caching/caching-movie-app","620"),exact:!0},{path:"/howtos/solutions/caching-architecture/common-caching/redis-gears",component:p("/howtos/solutions/caching-architecture/common-caching/redis-gears","411"),exact:!0},{path:"/howtos/solutions/caching-architecture/common-caching/source-code-movie-app",component:p("/howtos/solutions/caching-architecture/common-caching/source-code-movie-app","378"),exact:!0},{path:"/howtos/solutions/caching-architecture/common-caching/write-behind-vs-write-through",component:p("/howtos/solutions/caching-architecture/common-caching/write-behind-vs-write-through","8f2"),exact:!0},{path:"/howtos/solutions/caching-architecture/write-behind",component:p("/howtos/solutions/caching-architecture/write-behind","a0e"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/caching-architecture/write-through",component:p("/howtos/solutions/caching-architecture/write-through","31d"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/fraud-detection/common-fraud/source-code-tip",component:p("/howtos/solutions/fraud-detection/common-fraud/source-code-tip","f55"),exact:!0},{path:"/howtos/solutions/fraud-detection/digital-identity-validation",component:p("/howtos/solutions/fraud-detection/digital-identity-validation","e0a"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/fraud-detection/transaction-risk-scoring",component:p("/howtos/solutions/fraud-detection/transaction-risk-scoring","9d0"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/microservices/api-gateway-caching",component:p("/howtos/solutions/microservices/api-gateway-caching","843"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/microservices/caching",component:p("/howtos/solutions/microservices/caching","10b"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/microservices/common-data/microservices-arch",component:p("/howtos/solutions/microservices/common-data/microservices-arch","b0f"),exact:!0},{path:"/howtos/solutions/microservices/common-data/microservices-arch-with-redis",component:p("/howtos/solutions/microservices/common-data/microservices-arch-with-redis","fa3"),exact:!0},{path:"/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old",component:p("/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old","f20"),exact:!0},{path:"/howtos/solutions/microservices/common-data/microservices-ecommerce",component:p("/howtos/solutions/microservices/common-data/microservices-ecommerce","52f"),exact:!0},{path:"/howtos/solutions/microservices/common-data/microservices-ecommerce-old",component:p("/howtos/solutions/microservices/common-data/microservices-ecommerce-old","18d"),exact:!0},{path:"/howtos/solutions/microservices/common-data/microservices-source-code-tip",component:p("/howtos/solutions/microservices/common-data/microservices-source-code-tip","d37"),exact:!0},{path:"/howtos/solutions/microservices/common-data/microservices-source-code-tip-old",component:p("/howtos/solutions/microservices/common-data/microservices-source-code-tip-old","20a"),exact:!0},{path:"/howtos/solutions/microservices/common-data/redis-enterprise",component:p("/howtos/solutions/microservices/common-data/redis-enterprise","7f0"),exact:!0},{path:"/howtos/solutions/microservices/cqrs",component:p("/howtos/solutions/microservices/cqrs","192"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/microservices/interservice-communication",component:p("/howtos/solutions/microservices/interservice-communication","fe6"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/mobile-banking/account-dashboard",component:p("/howtos/solutions/mobile-banking/account-dashboard","1ea"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/mobile-banking/common-mb/additional-resources",component:p("/howtos/solutions/mobile-banking/common-mb/additional-resources","967"),exact:!0},{path:"/howtos/solutions/mobile-banking/common-mb/data-seeding",component:p("/howtos/solutions/mobile-banking/common-mb/data-seeding","893"),exact:!0},{path:"/howtos/solutions/mobile-banking/common-mb/source-code-tip",component:p("/howtos/solutions/mobile-banking/common-mb/source-code-tip","217"),exact:!0},{path:"/howtos/solutions/mobile-banking/session-management",component:p("/howtos/solutions/mobile-banking/session-management","364"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/real-time-inventory/available-to-promise",component:p("/howtos/solutions/real-time-inventory/available-to-promise","5f0"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-many-skus",component:p("/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-many-skus","2a8"),exact:!0},{path:"/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-sku",component:p("/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-sku","1e3"),exact:!0},{path:"/howtos/solutions/real-time-inventory/available-to-promise/api/increment-sku",component:p("/howtos/solutions/real-time-inventory/available-to-promise/api/increment-sku","e1b"),exact:!0},{path:"/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-many-skus",component:p("/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-many-skus","ea2"),exact:!0},{path:"/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-sku",component:p("/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-sku","a63"),exact:!0},{path:"/howtos/solutions/real-time-inventory/available-to-promise/api/update-sku",component:p("/howtos/solutions/real-time-inventory/available-to-promise/api/update-sku","7e8"),exact:!0},{path:"/howtos/solutions/real-time-inventory/common-rti/additional-resources",component:p("/howtos/solutions/real-time-inventory/common-rti/additional-resources","b98"),exact:!0},{path:"/howtos/solutions/real-time-inventory/common-rti/customer-proofs",component:p("/howtos/solutions/real-time-inventory/common-rti/customer-proofs","031"),exact:!0},{path:"/howtos/solutions/real-time-inventory/common-rti/rti-challenges",component:p("/howtos/solutions/real-time-inventory/common-rti/rti-challenges","c89"),exact:!0},{path:"/howtos/solutions/real-time-inventory/common-rti/source-code-tip",component:p("/howtos/solutions/real-time-inventory/common-rti/source-code-tip","f58"),exact:!0},{path:"/howtos/solutions/real-time-inventory/local-inventory-search",component:p("/howtos/solutions/real-time-inventory/local-inventory-search","e59"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search",component:p("/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search","ad4"),exact:!0},{path:"/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search-with-distance",component:p("/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search-with-distance","135"),exact:!0},{path:"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai",component:p("/howtos/solutions/vector/common-ai/microservices-ecommerce-ai","d33"),exact:!0},{path:"/howtos/solutions/vector/common-ai/microservices-source-code-ai",component:p("/howtos/solutions/vector/common-ai/microservices-source-code-ai","ac7"),exact:!0},{path:"/howtos/solutions/vector/gen-ai-chatbot",component:p("/howtos/solutions/vector/gen-ai-chatbot","81e"),exact:!0,sidebar:"docs"},{path:"/howtos/solutions/vector/getting-started-vector",component:p("/howtos/solutions/vector/getting-started-vector","f0e"),exact:!0,sidebar:"docs"},{path:"/modules/index-modules",component:p("/modules/index-modules","f32"),exact:!0},{path:"/modules/redisbloom",component:p("/modules/redisbloom","93d"),exact:!0},{path:"/modules/redisearch",component:p("/modules/redisearch","71a"),exact:!0},{path:"/modules/redisgears",component:p("/modules/redisgears","b3d"),exact:!0},{path:"/modules/redisgraph",component:p("/modules/redisgraph","a10"),exact:!0},{path:"/modules/redisjson",component:p("/modules/redisjson","e0c"),exact:!0},{path:"/modules/redistimeseries",component:p("/modules/redistimeseries","279"),exact:!0},{path:"/operate/docker/nodejs-nginx-redis",component:p("/operate/docker/nodejs-nginx-redis","2b9"),exact:!0,sidebar:"docs"},{path:"/operate/observability/datadog",component:p("/operate/observability/datadog","6bb"),exact:!0,sidebar:"docs"},{path:"/operate/observability/redisdatasource",component:p("/operate/observability/redisdatasource","4e5"),exact:!0,sidebar:"docs"},{path:"/operate/orchestration",component:p("/operate/orchestration","d21"),exact:!0,sidebar:"docs"},{path:"/operate/orchestration/docker/",component:p("/operate/orchestration/docker/","b9f"),exact:!0,sidebar:"docs"},{path:"/operate/orchestration/docker/images/",component:p("/operate/orchestration/docker/images/","cfc"),exact:!0},{path:"/operate/orchestration/kubernetes-operator",component:p("/operate/orchestration/kubernetes-operator","86b"),exact:!0,sidebar:"docs"},{path:"/operate/orchestration/kubernetes/kubernetes-gke",component:p("/operate/orchestration/kubernetes/kubernetes-gke","c58"),exact:!0,sidebar:"docs"},{path:"/operate/provisioning/terraform",component:p("/operate/provisioning/terraform","6e3"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale",component:p("/operate/redis-at-scale","17d"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/course-wrap-up/",component:p("/operate/redis-at-scale/course-wrap-up/","44c"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/high-availability",component:p("/operate/redis-at-scale/high-availability","241"),exact:!0},{path:"/operate/redis-at-scale/high-availability/basic-replication",component:p("/operate/redis-at-scale/high-availability/basic-replication","4b1"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/high-availability/exercise-1",component:p("/operate/redis-at-scale/high-availability/exercise-1","72c"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/high-availability/exercise-2",component:p("/operate/redis-at-scale/high-availability/exercise-2","aea"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/high-availability/introduction",component:p("/operate/redis-at-scale/high-availability/introduction","d32"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/high-availability/understanding-sentinels",component:p("/operate/redis-at-scale/high-availability/understanding-sentinels","ff7"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/observability",component:p("/operate/redis-at-scale/observability","938"),exact:!0},{path:"/operate/redis-at-scale/observability/data-points-in-redis",component:p("/operate/redis-at-scale/observability/data-points-in-redis","a4e"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/observability/exercise-1",component:p("/operate/redis-at-scale/observability/exercise-1","514"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/observability/identifying-issues",component:p("/operate/redis-at-scale/observability/identifying-issues","912"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/observability/introduction",component:p("/operate/redis-at-scale/observability/introduction","12f"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/persistence-and-durability",component:p("/operate/redis-at-scale/persistence-and-durability","5e5"),exact:!0},{path:"/operate/redis-at-scale/persistence-and-durability/exercise",component:p("/operate/redis-at-scale/persistence-and-durability/exercise","1fd"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/persistence-and-durability/introduction",component:p("/operate/redis-at-scale/persistence-and-durability/introduction","be2"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis",component:p("/operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis","973"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/scalability",component:p("/operate/redis-at-scale/scalability","400"),exact:!0},{path:"/operate/redis-at-scale/scalability/exercise-1",component:p("/operate/redis-at-scale/scalability/exercise-1","f72"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/scalability/lustering-in-redis",component:p("/operate/redis-at-scale/scalability/lustering-in-redis","8f6"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/scalability/redis-cli-with-redis-cluster",component:p("/operate/redis-at-scale/scalability/redis-cli-with-redis-cluster","2fc"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/scalability/redis-cluster-and-client-libraries",component:p("/operate/redis-at-scale/scalability/redis-cluster-and-client-libraries","86c"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/talking-to-redis",component:p("/operate/redis-at-scale/talking-to-redis","566"),exact:!0},{path:"/operate/redis-at-scale/talking-to-redis/client-performance-improvements",component:p("/operate/redis-at-scale/talking-to-redis/client-performance-improvements","f07"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/talking-to-redis/command-line-tool",component:p("/operate/redis-at-scale/talking-to-redis/command-line-tool","36f"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/talking-to-redis/configuring-a-redis-server",component:p("/operate/redis-at-scale/talking-to-redis/configuring-a-redis-server","8f6"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/talking-to-redis/initial-tuning",component:p("/operate/redis-at-scale/talking-to-redis/initial-tuning","603"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/talking-to-redis/redis-clients",component:p("/operate/redis-at-scale/talking-to-redis/redis-clients","6c3"),exact:!0,sidebar:"docs"},{path:"/operate/redis-at-scale/talking-to-redis/redis-server-overview",component:p("/operate/redis-at-scale/talking-to-redis/redis-server-overview","dd8"),exact:!0,sidebar:"docs"},{path:"/redis-insiders/",component:p("/redis-insiders/","ead"),exact:!0,sidebar:"docs"},{path:"/redis-insiders/jyotsna-gupta/",component:p("/redis-insiders/jyotsna-gupta/","80f"),exact:!0,sidebar:"docs"},{path:"/redis-insiders/michael-owolabi/",component:p("/redis-insiders/michael-owolabi/","8f6"),exact:!0,sidebar:"docs"},{path:"/redis-insiders/moiz-kapasi/",component:p("/redis-insiders/moiz-kapasi/","b7e"),exact:!0,sidebar:"docs"},{path:"/redis-insiders/stevan-thomas/",component:p("/redis-insiders/stevan-thomas/","bd4"),exact:!0,sidebar:"docs"},{path:"/redis-live/",component:p("/redis-live/","499"),exact:!0,sidebar:"docs"},{path:"/tools/index-tools",component:p("/tools/index-tools","c3f"),exact:!0},{path:"/tools/riot",component:p("/tools/riot","09c"),exact:!0},{path:"/tutorials/redisearch/getting-started/",component:p("/tutorials/redisearch/getting-started/","e4d"),exact:!0}]},{path:"*",component:p("*")}]},98934:(e,t,n)=>{"use strict";n.d(t,{_:()=>o,t:()=>a});var r=n(67294);const o=r.createContext(!1);function a(e){let{children:t}=e;const[n,a]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{a(!0)}),[]),r.createElement(o.Provider,{value:n},t)}},49383:(e,t,n)=>{"use strict";var r=n(67294),o=n(73935),a=n(73727),i=n(70405),s=n(10412);const c=[n(32497),n(3310),n(18320),n(93878)];var l=n(723),d=n(76775),u=n(18790);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var h=n(87462),m=n(35742),f=n(52263),g=n(44996),b=n(86668),v=n(1944),y=n(94711),w=n(19727),x=n(43320),k=n(90197);function E(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,f.Z)(),n=(0,y.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:o}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:o})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,f.Z)(),o=function(){const{siteConfig:{url:e}}=(0,f.Z)(),{pathname:t}=(0,d.TH)();return e+(0,g.Z)(t)}(),a=t?`${n}${t}`:o;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:a}),r.createElement("link",{rel:"canonical",href:a}))}function S(){const{i18n:{currentLocale:e}}=(0,f.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(m.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(v.d,{image:n}),r.createElement(_,null),r.createElement(E,null),r.createElement(k.Z,{tag:x.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,h.Z)({key:t},e))))))}const T=new Map;function C(e){if(T.has(e.pathname))return{...e,pathname:T.get(e.pathname)};if((0,u.f)(l.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return T.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return T.set(e.pathname,t),{...e,pathname:t}}var A=n(98934),P=n(58940);function R(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{var r;const o=(null==(r=t.default)?void 0:r[e])??t[e];return null==o?void 0:o(...n)}));return()=>o.forEach((e=>null==e?void 0:e()))}const L=function(e){let{children:t,location:n,previousLocation:o}=e;return(0,r.useLayoutEffect)((()=>{o!==n&&(o&&function(e){const{hash:t}=e;if(t){const e=decodeURIComponent(t.substring(1)),n=document.getElementById(e);null==n||n.scrollIntoView()}else window.scrollTo(0,0)}(n),R("onRouteDidUpdate",{previousLocation:o,location:n}))}),[o,n]),t};function N(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,u.f)(l.Z,e))).flat();return Promise.all(t.map((e=>null==e.route.component.preload?void 0:e.route.component.preload())))}class I extends r.Component{constructor(e){super(e),this.previousLocation=void 0,this.routeUpdateCleanupCb=void 0,this.previousLocation=null,this.routeUpdateCleanupCb=s.Z.canUseDOM?R("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=R("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),N(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(L,{previousLocation:this.previousLocation,location:t},r.createElement(d.AW,{location:t,render:()=>e}))}}const O=I,j="docusaurus-base-url-issue-banner-container",D="docusaurus-base-url-issue-banner-suggestion-container",M="__DOCUSAURUS_INSERT_BASEURL_BANNER";function F(e){return`\nwindow['${M}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${M}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${j}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n

\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/{window[M]=!1}),[]),r.createElement(r.Fragment,null,!s.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,F(e))),r.createElement("div",{id:j}))}function z(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,f.Z)(),{pathname:n}=(0,d.TH)();return t&&n===e?r.createElement(B,null):null}function U(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:o,localeConfigs:a}}=(0,f.Z)(),i=(0,g.Z)(e),{htmlLang:s,direction:c}=a[o];return r.createElement(m.Z,null,r.createElement("html",{lang:s,dir:c}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var $=n(44763);function q(){const e=(0,u.H)(l.Z),t=(0,d.TH)();return r.createElement($.Z,null,r.createElement(P.M,null,r.createElement(A.t,null,r.createElement(p,null,r.createElement(U,null),r.createElement(S,null),r.createElement(z,null),r.createElement(O,{location:C(t)},e)))))}var H=n(16887);const Z=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{var r;if("undefined"==typeof document)return void n();const o=document.createElement("link");o.setAttribute("rel","prefetch"),o.setAttribute("href",e),o.onload=()=>t(),o.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??(null==(r=document.getElementsByName("script")[0])?void 0:r.parentNode);null==a||a.appendChild(o)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var G=n(99670);const V=new Set,W=new Set,Y=()=>{var e,t;return(null==(e=navigator.connection)?void 0:e.effectiveType.includes("2g"))||(null==(t=navigator.connection)?void 0:t.saveData)},K={prefetch(e){if(!(e=>!Y()&&!W.has(e)&&!V.has(e))(e))return!1;V.add(e);const t=(0,u.f)(l.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(H).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,G.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Z(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!Y()&&!W.has(e))(e)&&(W.add(e),N(e))},X=Object.freeze(K);if(s.Z.canUseDOM){window.docusaurus=X;const e=o.hydrate;N(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(a.VK,null,r.createElement(q,null))),document.getElementById("__docusaurus"))}))}},58940:(e,t,n)=>{"use strict";n.d(t,{_:()=>d,M:()=>u});var r=n(67294),o=n(36809);const a=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/","versions":[{"name":"current","label":"Next","isLast":true,"path":"/","mainDocId":"howtos/quick-start/index-quick-start","docs":[{"id":"create/aws/analytics-using-aws/index-analytics-using-aws","path":"/create/aws/analytics-using-aws","sidebar":"docs"},{"id":"create/aws/bidding-on-aws/index-bidding-on-aws","path":"/create/aws/bidding-on-aws","sidebar":"docs"},{"id":"create/aws/chatapp/index-chatapp","path":"/create/aws/chatapp","sidebar":"docs"},{"id":"create/aws/import/index-database-migration-aws-elasticache-redis-enterprise-cloud","path":"/create/aws/import/database-migration-aws-elasticache-redis-enterprise-cloud/","sidebar":"docs"},{"id":"create/aws/index-aws","path":"/create/aws","sidebar":"docs"},{"id":"create/aws/README","path":"/create/aws/"},{"id":"create/aws/redis-on-aws/images/README","path":"/create/aws/redis-on-aws/images/"},{"id":"create/aws/redis-on-aws/index-redis-on-aws","path":"/create/aws/redis-on-aws","sidebar":"docs"},{"id":"create/aws/redis-on-aws/README","path":"/create/aws/redis-on-aws/"},{"id":"create/aws/slackbot/index-slackbot","path":"/create/aws/slackbot","sidebar":"docs"},{"id":"create/aws/terraform/index-terraform","path":"/create/aws/terraform","sidebar":"docs"},{"id":"create/azure/index-azure","path":"/create/azure","sidebar":"docs"},{"id":"create/azure/portal/index-azure-portal","path":"/create/azure/portal","sidebar":"docs"},{"id":"create/azurefunctions/index-azurefunctions","path":"/create/azurefunctions","sidebar":"docs"},{"id":"create/cloud/aws/index-aws","path":"/create/cloud/aws"},{"id":"create/cloud/azure/index-azure","path":"/create/cloud/azure"},{"id":"create/cloud/gcp/index-gcp","path":"/create/cloud/gcp"},{"id":"create/cloud/images/README","path":"/create/cloud/images/"},{"id":"create/cloud/index-cloud","path":"/create/cloud/"},{"id":"create/cloud/rediscloud/images/README","path":"/create/cloud/rediscloud/images/"},{"id":"create/cloud/rediscloud/index-rediscloud","path":"/create/cloud/rediscloud"},{"id":"create/docker/index-docker","path":"/create/docker/","sidebar":"docs"},{"id":"create/docker/nodejs-nginx-redis/index-nodejs-nginx-redis","path":"/create/docker/nodejs-nginx-redis","sidebar":"docs"},{"id":"create/heroku/index-heroku","path":"/create/heroku"},{"id":"create/heroku/portal/index-heroku-portal","path":"/create/heroku/portal"},{"id":"create/images/README","path":"/create/images/"},{"id":"create/index-create","path":"/create","sidebar":"docs"},{"id":"create/jenkins/index-jenkins","path":"/create/jenkins","sidebar":"docs"},{"id":"create/kubernetes/index-kubernetes","path":"/create/kubernetes/","sidebar":"docs"},{"id":"create/kubernetes/kubernetes-operator/index-kubernetes-operator","path":"/create/kubernetes/kubernetes-operator"},{"id":"create/openshift/index-openshift","path":"/create/openshift"},{"id":"create/redis-functions/index-redis-functions","path":"/create/redis-functions","sidebar":"docs"},{"id":"create/windows/index-windows","path":"/create/windows","sidebar":"docs"},{"id":"develop/C/index-c","path":"/develop/C/","sidebar":"docs"},{"id":"develop/deno/index-deno","path":"/develop/deno/","sidebar":"docs"},{"id":"develop/dotnet/aspnetcore/caching/basic/index-basic-caching","path":"/develop/dotnet/aspnetcore/caching/basic-api-caching","sidebar":"docs"},{"id":"develop/dotnet/aspnetcore/rate-limiting/fixed-window/index-dotnet-rate-limiting","path":"/develop/dotnet/aspnetcore/rate-limiting/fixed-window","sidebar":"docs"},{"id":"develop/dotnet/aspnetcore/rate-limiting/middleware/byo-rate-limiter-middleware","path":"/develop/dotnet/aspnetcore/rate-limiting/middleware","sidebar":"docs"},{"id":"develop/dotnet/aspnetcore/rate-limiting/sliding-window/sliding-window-rate-limiting","path":"/develop/dotnet/aspnetcore/rate-limiting/sliding-window","sidebar":"docs"},{"id":"develop/dotnet/index-dotnet","path":"/develop/dotnet"},{"id":"develop/dotnet/redis-om-dotnet/add-and-retrieve-objects/add-and-retrieve-objects","path":"/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/aggregations/apply-functions/apply-functions","path":"/develop/dotnet/redis-om-dotnet/aggregations/apply-functions","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/aggregations/groups/groups","path":"/develop/dotnet/redis-om-dotnet/aggregations/groups/groups","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/aggregations/intro/intro","path":"/develop/dotnet/redis-om-dotnet/aggregations","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/creating-an-index/creating-an-index","path":"/develop/dotnet/redis-om-dotnet/searching/creating-an-index","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/searching/geo-filters/geo-filters","path":"/develop/dotnet/redis-om-dotnet/searching/geo-filters","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/searching/numeric-queries/numeric-queries","path":"/develop/dotnet/redis-om-dotnet/searching/numeric-queries","sidebar":"docs"},{"id":"develop/dotnet/redis-om-dotnet/searching/simple-text-queries/simple-text-queries","path":"/develop/dotnet/redis-om-dotnet/simple-text-queries","sidebar":"docs"},{"id":"develop/dotnet/streams/stream-basics","path":"/develop/dotnet/streams/stream-basics","sidebar":"docs"},{"id":"develop/guides/netlify/getting-started/index-getting-started","path":"/develop/guides/netlify/getting-started"},{"id":"develop/index-develop","path":"/develop","sidebar":"docs"},{"id":"develop/java/getting-started/index-gettingstarted","path":"/develop/java/getting-started"},{"id":"develop/java/index-java","path":"/develop/java","sidebar":"docs"},{"id":"develop/java/spring/index-spring","path":"/develop/java/spring/","sidebar":"docs"},{"id":"develop/java/spring/index-spring","path":"/develop/java/spring","sidebar":"docs"},{"id":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window","path":"/develop/java/spring/rate-limiting/fixed-window","sidebar":"docs"},{"id":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive","path":"/develop/java/spring/rate-limiting/fixed-window/reactive","sidebar":"docs"},{"id":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive-gears","path":"/develop/java/spring/rate-limiting/fixed-window/reactive-gears","sidebar":"docs"},{"id":"develop/java/spring/rate-limiting/fixed-window/index-spring-fixed-window-reactive-lua","path":"/develop/java/spring/rate-limiting/fixed-window/reactive-lua","sidebar":"docs"},{"id":"develop/java/spring/rate-limiting/getting-started/index-java-rate-limiting","path":"/develop/java/spring/rate-limiting/getting-started"},{"id":"develop/java/spring/rate-limiting/index-ratelimiting","path":"/develop/java/spring/rate-limiting","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/index-redis-and-spring-course","path":"/develop/java/redis-and-spring-course","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_1/index-lesson_1","path":"/develop/java/redis-and-spring-course/lesson_1","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_2/index-lesson_2","path":"/develop/java/redis-and-spring-course/lesson_2","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_3/index-lesson_3","path":"/develop/java/redis-and-spring-course/lesson_3","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_4/index-lesson_4","path":"/develop/java/redis-and-spring-course/lesson_4","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_5/index-lesson_5","path":"/develop/java/redis-and-spring-course/lesson_5","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_6/index-lesson_6","path":"/develop/java/redis-and-spring-course/lesson_6","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_7/index-lesson_7","path":"/develop/java/redis-and-spring-course/lesson_7","sidebar":"docs"},{"id":"develop/java/spring/redis-and-spring-course/lesson_9/index-lesson_9","path":"/develop/java/redis-and-spring-course/lesson_9","sidebar":"docs"},{"id":"develop/java/spring/redis-om/redis-om-spring","path":"/develop/java/spring/redis-om/redis-om-spring","sidebar":"docs"},{"id":"develop/java/spring/redis-om/redis-om-spring-hash","path":"/develop/java/spring/redis-om/redis-om-spring-hash","sidebar":"docs"},{"id":"develop/java/spring/redis-om/redis-om-spring-json","path":"/develop/java/spring/redis-om/redis-om-spring-json","sidebar":"docs"},{"id":"develop/node/gettingstarted/index-gettingstarted","path":"/develop/node/gettingstarted","sidebar":"docs"},{"id":"develop/node/index-node","path":"/develop/node","sidebar":"docs"},{"id":"develop/node/node-crash-course/advancedstreams/index-advancedstreams","path":"/develop/node/nodecrashcourse/advancedstreams","sidebar":"docs"},{"id":"develop/node/node-crash-course/caching/index-caching","path":"/develop/node/nodecrashcourse/caching","sidebar":"docs"},{"id":"develop/node/node-crash-course/checkinswithstreams/index-checkinswithstreams","path":"/develop/node/nodecrashcourse/checkinswithstreams","sidebar":"docs"},{"id":"develop/node/node-crash-course/coursewrapup/index-coursewrapup","path":"/develop/node/nodecrashcourse/coursewrapup","sidebar":"docs"},{"id":"develop/node/node-crash-course/domainobjectswithhashes/index-domainobjectswithhashes","path":"/develop/node/nodecrashcourse/domainobjectswithhashes","sidebar":"docs"},{"id":"develop/node/node-crash-course/index-node-crash-course","path":"/develop/node/node-crash-course","sidebar":"docs"},{"id":"develop/node/node-crash-course/introducingredisinsight/index-introducingredisinsight","path":"/develop/node/nodecrashcourse/introducingredisinsight","sidebar":"docs"},{"id":"develop/node/node-crash-course/introductiontomodules/index-introductiontomodules","path":"/develop/node/nodecrashcourse/introductiontomodules","sidebar":"docs"},{"id":"develop/node/node-crash-course/managingsuccess/index-managingsuccess","path":"/develop/node/nodecrashcourse/managingsuccess","sidebar":"docs"},{"id":"develop/node/node-crash-course/redisandnodejs/index-redisandnodejs","path":"/develop/node/nodecrashcourse/redisandnodejs","sidebar":"docs"},{"id":"develop/node/node-crash-course/redisbloom/index-redisbloom","path":"/develop/node/nodecrashcourse/redisbloom","sidebar":"docs"},{"id":"develop/node/node-crash-course/redisearch/index-redisearch","path":"/develop/node/nodecrashcourse/redisearch","sidebar":"docs"},{"id":"develop/node/node-crash-course/redisjson/index-redisjson","path":"/develop/node/nodecrashcourse/redisjson","sidebar":"docs"},{"id":"develop/node/node-crash-course/runningtheapplication/index-runningtheapplication","path":"/develop/node/nodecrashcourse/runningtheapplication","sidebar":"docs"},{"id":"develop/node/node-crash-course/sampleapplicationoverview/index-sampleapplicationoverview","path":"/develop/node/nodecrashcourse/sampleapplicationoverview","sidebar":"docs"},{"id":"develop/node/node-crash-course/sessionstorage/index-sessionstorage","path":"/develop/node/nodecrashcourse/sessionstorage","sidebar":"docs"},{"id":"develop/node/node-crash-course/welcome/index-welcome","path":"/develop/node/nodecrashcourse/welcome","sidebar":"docs"},{"id":"develop/node/node-crash-course/whatisredis/index-whatisredis","path":"/develop/node/nodecrashcourse/whatisredis","sidebar":"docs"},{"id":"develop/node/redis-om/index-redis-om","path":"/develop/node/redis-om","sidebar":"docs"},{"id":"develop/php/index-php","path":"/develop/php/","sidebar":"docs"},{"id":"develop/python/fastapi/index-fastapi","path":"/develop/python/fastapi","sidebar":"docs"},{"id":"develop/python/redis-om/index-redis-om","path":"/develop/python/redis-om"},{"id":"develop/ruby/index-ruby","path":"/develop/ruby/","sidebar":"docs"},{"id":"develop/rust/index-rust","path":"/develop/rust/"},{"id":"ebooks/nosql-data-modeling-patterns","path":"/ebooks/8-nosql-data-modeling-patterns","sidebar":"docs"},{"id":"ebooks/three-caching-design-patterns","path":"/ebooks/three-caching-design-patterns","sidebar":"docs"},{"id":"explore/datadog/index-datadog","path":"/explore/datadog","sidebar":"docs"},{"id":"explore/import/index-import","path":"/explore/import/","sidebar":"docs"},{"id":"explore/index-explore","path":"/explore","sidebar":"docs"},{"id":"explore/redisdatasource/index-redisdatasource","path":"/explore/redisdatasource","sidebar":"docs"},{"id":"explore/riot/index-riot","path":"/explore/riot","sidebar":"docs"},{"id":"get-involved/devcember/index-devcember","path":"/devcember/","sidebar":"docs"},{"id":"get-involved/discord/index-discord","path":"/community/discord/","sidebar":"docs"},{"id":"get-involved/hacktoberfest/index-hacktoberfest","path":"/hacktoberfest/","sidebar":"docs"},{"id":"get-involved/hacktoberfest/lara-aasem-story/index-lara-aasem-story","path":"/hacktoberfest/stories/lara-aasem","sidebar":"docs"},{"id":"get-involved/hacktoberfest/vincent-aceto-story/index-vincent-aceto-story","path":"/hacktoberfest/stories/vincent-aceto","sidebar":"docs"},{"id":"get-involved/index-getinvolved","path":"/community/","sidebar":"docs"},{"id":"get-involved/redis-insiders/index-redis-insiders","path":"/redis-insiders/","sidebar":"docs"},{"id":"get-involved/redis-insiders/jyotsna-gupta/index-jyotsna-gupta","path":"/redis-insiders/jyotsna-gupta/","sidebar":"docs"},{"id":"get-involved/redis-insiders/michael-owolabi/index-michael-owolabi","path":"/redis-insiders/michael-owolabi/","sidebar":"docs"},{"id":"get-involved/redis-insiders/moiz-kapasi/index-moiz-kapasi","path":"/redis-insiders/moiz-kapasi/","sidebar":"docs"},{"id":"get-involved/redis-insiders/stevan-thomas/index-stevan-thomas","path":"/redis-insiders/stevan-thomas/","sidebar":"docs"},{"id":"get-involved/redis-live/index-redis-live","path":"/redis-live/","sidebar":"docs"},{"id":"guides/data-modeling/index-data-modeling","path":"/guides/data-modeling/"},{"id":"guides/import-data","path":"/guides/import-data/"},{"id":"guides/import/database-migration-aws-elasticache-redis-enterprise-cloud","path":"/guides/import/database-migration-aws-elasticache-redis-enterprise-cloud/"},{"id":"guides/import/index-import","path":"/guides/import/"},{"id":"guides/index-guides","path":"/guides/"},{"id":"guides/indexing/indexing-querying","path":"/guides/indexing/"},{"id":"guides/security/how-to-use-tls-with-redis-enterprise/how-to-use-ssl-tls-with-redis-enterprise","path":"/guide/security/how-to-use-ssl-tls-with-redis-enterprise/"},{"id":"guides/security/index-security","path":"/guides/security/"},{"id":"howtos/analytics/index-analytics","path":"/howtos/analytics","sidebar":"docs"},{"id":"howtos/antipatterns/index-antipatterns","path":"/howtos/antipatterns/","sidebar":"docs"},{"id":"howtos/bert-qa-benchmarking/bert-qa-benchmarking-with-redisai-and-redisgears","path":"/howtos/redisai/bert-qa-benchmarking-with-redisai-and-redisgears","sidebar":"docs"},{"id":"howtos/caching/index-caching","path":"/howtos/caching","sidebar":"docs"},{"id":"howtos/chatapp/index-chatapp","path":"/howtos/chatapp","sidebar":"docs"},{"id":"howtos/frauddetection/index-frauddetection","path":"/howtos/frauddetection","sidebar":"docs"},{"id":"howtos/hackernews/index-hackernews","path":"/howtos/hackernews","sidebar":"docs"},{"id":"howtos/herokujava/index-herokujava","path":"/howtos/herokujava","sidebar":"docs"},{"id":"howtos/herokunodejs/index-herokunodejs","path":"/howtos/herokunodejs","sidebar":"docs"},{"id":"howtos/herokupython/index-herokupython","path":"/howtos/herokupython","sidebar":"docs"},{"id":"howtos/index-modules","path":"/howtos/index-modules"},{"id":"howtos/leaderboard/index-leaderboard","path":"/howtos/leaderboard","sidebar":"docs"},{"id":"howtos/moviesdatabase/advancedoption/index-advancedoption","path":"/howtos/moviesdatabase/advancedoption","sidebar":"docs"},{"id":"howtos/moviesdatabase/aggregation/index-aggregation","path":"/howtos/moviesdatabase/aggregation","sidebar":"docs"},{"id":"howtos/moviesdatabase/create/index-create","path":"/howtos/moviesdatabase/create","sidebar":"docs"},{"id":"howtos/moviesdatabase/import/index-import","path":"/howtos/moviesdatabase/import","sidebar":"docs"},{"id":"howtos/moviesdatabase/index-moviesdatabase","path":"/howtos/moviesdatabase"},{"id":"howtos/moviesdatabase/install/index-install","path":"/howtos/moviesdatabase/install","sidebar":"docs"},{"id":"howtos/moviesdatabase/manage/index-manage","path":"/howtos/moviesdatabase/manage","sidebar":"docs"},{"id":"howtos/moviesdatabase/query/index-query","path":"/howtos/moviesdatabase/query","sidebar":"docs"},{"id":"howtos/moviesdatabase/querymovies/index-querymovies","path":"/howtos/moviesdatabase/querymovies","sidebar":"docs"},{"id":"howtos/moviesdatabase/sampleapp/index-sampleapp","path":"/howtos/moviesdatabase/sampleapp","sidebar":"docs"},{"id":"howtos/nlp/index-nlp","path":"/howtos/nlp","sidebar":"docs"},{"id":"howtos/popupstore/index-popupstore","path":"/howtos/popupstore","sidebar":"docs"},{"id":"howtos/quick-start/cheat-sheets/connect","path":"/howtos/quick-start/cheat-sheets/connect"},{"id":"howtos/quick-start/cheat-sheets/generic","path":"/howtos/quick-start/cheat-sheets/generic"},{"id":"howtos/quick-start/cheat-sheets/hashes","path":"/howtos/quick-start/cheat-sheets/hashes"},{"id":"howtos/quick-start/cheat-sheets/index-quick-start-cheat-sheet","path":"/howtos/quick-start/cheat-sheet","sidebar":"docs"},{"id":"howtos/quick-start/cheat-sheets/json","path":"/howtos/quick-start/cheat-sheets/json"},{"id":"howtos/quick-start/cheat-sheets/lists","path":"/howtos/quick-start/cheat-sheets/lists"},{"id":"howtos/quick-start/cheat-sheets/search-and-query","path":"/howtos/quick-start/cheat-sheets/search-and-query"},{"id":"howtos/quick-start/cheat-sheets/sets","path":"/howtos/quick-start/cheat-sheets/sets"},{"id":"howtos/quick-start/cheat-sheets/sorted-sets","path":"/howtos/quick-start/cheat-sheets/sorted-sets"},{"id":"howtos/quick-start/cheat-sheets/streams","path":"/howtos/quick-start/cheat-sheets/streams"},{"id":"howtos/quick-start/cheat-sheets/strings","path":"/howtos/quick-start/cheat-sheets/strings"},{"id":"howtos/quick-start/cheat-sheets/triggers-and-functions","path":"/howtos/quick-start/cheat-sheets/triggers-and-functions"},{"id":"howtos/quick-start/index-quick-start","path":"/howtos/quick-start","sidebar":"docs"},{"id":"howtos/ratelimiting/index-ratelimiting","path":"/howtos/ratelimiting","sidebar":"docs"},{"id":"howtos/redisgraph/csvtograph/index-csvtograph","path":"/howtos/redisgraph/csvtograph"},{"id":"howtos/redisgraph/explore-python-code/index-explorepythoncode","path":"/howtos/redisgraph/explore-python-code"},{"id":"howtos/redisgraph/getting-started/index-gettingstarted","path":"/howtos/redisgraph/getting-started"},{"id":"howtos/redisgraph/index-redisgraph","path":"/howtos/redisgraph/"},{"id":"howtos/redisgraph/redisgraph-cheatsheet/index-redisgraph-cheatsheet","path":"/howtos/redisgraph/redisgraph-cheatsheet"},{"id":"howtos/redisgraph/redisgraphmovies/index-redisgraphmovies","path":"/howtos/redisgraph/redisgraphmovies"},{"id":"howtos/redisgraph/using-dotnet/index-using-dotnet","path":"/howtos/redisgraph/using-dotnet"},{"id":"howtos/redisgraph/using-go/index-usinggo","path":"/howtos/redisgraph/using-go"},{"id":"howtos/redisgraph/using-javascript/index-usingjavascript","path":"/howtos/redisgraph/using-javascript"},{"id":"howtos/redisgraph/using-python/index-usingpython","path":"/howtos/redisgraph/using-python"},{"id":"howtos/redisgraph/using-redisinsight/index-usingredisinsight","path":"/howtos/redisgraph/using-redisinsight"},{"id":"howtos/redisgraph/using-ruby/index-usingruby","path":"/howtos/redisgraph/using-ruby"},{"id":"howtos/redisgraph/using-rust/index-usingrust","path":"/howtos/redisgraph/using-rust"},{"id":"howtos/security/index-tls","path":"/howtos/security/","sidebar":"docs"},{"id":"howtos/shoppingcart/index-shoppingcart","path":"/howtos/shoppingcart"},{"id":"howtos/socialnetwork/index-socialnetwork","path":"/howtos/socialnetwork/","sidebar":"docs"},{"id":"howtos/solutions/caching-architecture/cache-prefetching/index-cache-prefetching","path":"/howtos/solutions/caching-architecture/cache-prefetching","sidebar":"docs"},{"id":"howtos/solutions/caching-architecture/common-caching/caching-movie-app","path":"/howtos/solutions/caching-architecture/common-caching/caching-movie-app"},{"id":"howtos/solutions/caching-architecture/common-caching/redis-gears","path":"/howtos/solutions/caching-architecture/common-caching/redis-gears"},{"id":"howtos/solutions/caching-architecture/common-caching/source-code-movie-app","path":"/howtos/solutions/caching-architecture/common-caching/source-code-movie-app"},{"id":"howtos/solutions/caching-architecture/common-caching/write-behind-vs-write-through","path":"/howtos/solutions/caching-architecture/common-caching/write-behind-vs-write-through"},{"id":"howtos/solutions/caching-architecture/write-behind/index-write-behind","path":"/howtos/solutions/caching-architecture/write-behind","sidebar":"docs"},{"id":"howtos/solutions/caching-architecture/write-through/index-write-through","path":"/howtos/solutions/caching-architecture/write-through","sidebar":"docs"},{"id":"howtos/solutions/fraud-detection/common-fraud/source-code-tip","path":"/howtos/solutions/fraud-detection/common-fraud/source-code-tip"},{"id":"howtos/solutions/fraud-detection/digital-identity-validation/index-digital-identity-validation","path":"/howtos/solutions/fraud-detection/digital-identity-validation","sidebar":"docs"},{"id":"howtos/solutions/fraud-detection/transaction-risk-scoring/index-transaction-risk-scoring","path":"/howtos/solutions/fraud-detection/transaction-risk-scoring","sidebar":"docs"},{"id":"howtos/solutions/index-solutions","path":"/howtos/solutions","sidebar":"docs"},{"id":"howtos/solutions/microservices/api-gateway-caching/index-solutions-api-gateway-caching","path":"/howtos/solutions/microservices/api-gateway-caching","sidebar":"docs"},{"id":"howtos/solutions/microservices/caching/index-solutions-caching","path":"/howtos/solutions/microservices/caching","sidebar":"docs"},{"id":"howtos/solutions/microservices/common-data/microservices-arch","path":"/howtos/solutions/microservices/common-data/microservices-arch"},{"id":"howtos/solutions/microservices/common-data/microservices-arch-with-redis","path":"/howtos/solutions/microservices/common-data/microservices-arch-with-redis"},{"id":"howtos/solutions/microservices/common-data/microservices-arch-with-redis-old","path":"/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old"},{"id":"howtos/solutions/microservices/common-data/microservices-ecommerce","path":"/howtos/solutions/microservices/common-data/microservices-ecommerce"},{"id":"howtos/solutions/microservices/common-data/microservices-ecommerce-old","path":"/howtos/solutions/microservices/common-data/microservices-ecommerce-old"},{"id":"howtos/solutions/microservices/common-data/microservices-source-code-tip","path":"/howtos/solutions/microservices/common-data/microservices-source-code-tip"},{"id":"howtos/solutions/microservices/common-data/microservices-source-code-tip-old","path":"/howtos/solutions/microservices/common-data/microservices-source-code-tip-old"},{"id":"howtos/solutions/microservices/common-data/redis-enterprise","path":"/howtos/solutions/microservices/common-data/redis-enterprise"},{"id":"howtos/solutions/microservices/cqrs/index-solutions-cqrs","path":"/howtos/solutions/microservices/cqrs","sidebar":"docs"},{"id":"howtos/solutions/microservices/interservice-communication/index-solutions-interservice-communication","path":"/howtos/solutions/microservices/interservice-communication","sidebar":"docs"},{"id":"howtos/solutions/mobile-banking/account-dashboard/index-mb-account-dashboard","path":"/howtos/solutions/mobile-banking/account-dashboard","sidebar":"docs"},{"id":"howtos/solutions/mobile-banking/common-mb/additional-resources","path":"/howtos/solutions/mobile-banking/common-mb/additional-resources"},{"id":"howtos/solutions/mobile-banking/common-mb/data-seeding","path":"/howtos/solutions/mobile-banking/common-mb/data-seeding"},{"id":"howtos/solutions/mobile-banking/common-mb/source-code-tip","path":"/howtos/solutions/mobile-banking/common-mb/source-code-tip"},{"id":"howtos/solutions/mobile-banking/session-management/index-mb-session-management","path":"/howtos/solutions/mobile-banking/session-management","sidebar":"docs"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/api/decrement-many-skus","path":"/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-many-skus"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/api/decrement-sku","path":"/howtos/solutions/real-time-inventory/available-to-promise/api/decrement-sku"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/api/increment-sku","path":"/howtos/solutions/real-time-inventory/available-to-promise/api/increment-sku"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-many-skus","path":"/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-many-skus"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-sku","path":"/howtos/solutions/real-time-inventory/available-to-promise/api/retrieve-sku"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/api/update-sku","path":"/howtos/solutions/real-time-inventory/available-to-promise/api/update-sku"},{"id":"howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise","path":"/howtos/solutions/real-time-inventory/available-to-promise","sidebar":"docs"},{"id":"howtos/solutions/real-time-inventory/common-rti/additional-resources","path":"/howtos/solutions/real-time-inventory/common-rti/additional-resources"},{"id":"howtos/solutions/real-time-inventory/common-rti/customer-proofs","path":"/howtos/solutions/real-time-inventory/common-rti/customer-proofs"},{"id":"howtos/solutions/real-time-inventory/common-rti/rti-challenges","path":"/howtos/solutions/real-time-inventory/common-rti/rti-challenges"},{"id":"howtos/solutions/real-time-inventory/common-rti/source-code-tip","path":"/howtos/solutions/real-time-inventory/common-rti/source-code-tip"},{"id":"howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search","path":"/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search"},{"id":"howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search-with-distance","path":"/howtos/solutions/real-time-inventory/local-inventory-search/api/inventory-search-with-distance"},{"id":"howtos/solutions/real-time-inventory/local-inventory-search/index-rti-local-inventory-search","path":"/howtos/solutions/real-time-inventory/local-inventory-search","sidebar":"docs"},{"id":"howtos/solutions/vector/common-ai/microservices-ecommerce-ai","path":"/howtos/solutions/vector/common-ai/microservices-ecommerce-ai"},{"id":"howtos/solutions/vector/common-ai/microservices-source-code-ai","path":"/howtos/solutions/vector/common-ai/microservices-source-code-ai"},{"id":"howtos/solutions/vector/gen-ai-chatbot/index-solutions-gen-ai-chatbot","path":"/howtos/solutions/vector/gen-ai-chatbot","sidebar":"docs"},{"id":"howtos/solutions/vector/getting-started-vector/index-getting-started-vector","path":"/howtos/solutions/vector/getting-started-vector","sidebar":"docs"},{"id":"modules/index-modules","path":"/modules/index-modules"},{"id":"modules/redisbloom/index-redisbloom","path":"/modules/redisbloom"},{"id":"modules/redisearch/index-redisearch","path":"/modules/redisearch"},{"id":"modules/redisgears/index-redisgears","path":"/modules/redisgears"},{"id":"modules/redisgraph/index-redisgraph","path":"/modules/redisgraph"},{"id":"modules/redisjson/index-redisjson","path":"/modules/redisjson"},{"id":"modules/redistimeseries/index-redistimeseries","path":"/modules/redistimeseries"},{"id":"operate/observability/datadog/index-datadog","path":"/operate/observability/datadog","sidebar":"docs"},{"id":"operate/observability/redisdatasource/index-redisdatasource","path":"/operate/observability/redisdatasource","sidebar":"docs"},{"id":"operate/orchestration/docker/images/README","path":"/operate/orchestration/docker/images/"},{"id":"operate/orchestration/docker/index-docker","path":"/operate/orchestration/docker/","sidebar":"docs"},{"id":"operate/orchestration/index-orchestration","path":"/operate/orchestration","sidebar":"docs"},{"id":"operate/orchestration/kubernetes-gke/index-kubernetes-gke","path":"/operate/orchestration/kubernetes/kubernetes-gke","sidebar":"docs"},{"id":"operate/orchestration/kubernetes-operator/index-kubernetes-operator","path":"/operate/orchestration/kubernetes-operator","sidebar":"docs"},{"id":"operate/orchestration/nodejs-nginx-redis/index-nodejs-nginx-redis","path":"/operate/docker/nodejs-nginx-redis","sidebar":"docs"},{"id":"operate/provisioning/terraform/index-terraform","path":"/operate/provisioning/terraform","sidebar":"docs"},{"id":"operate/redis-at-scale/course-wrap-up/index-wrap-up","path":"/operate/redis-at-scale/course-wrap-up/","sidebar":"docs"},{"id":"operate/redis-at-scale/high-availability/basic-replication/index-basic-replication","path":"/operate/redis-at-scale/high-availability/basic-replication","sidebar":"docs"},{"id":"operate/redis-at-scale/high-availability/exercise-1/index-exercise-1","path":"/operate/redis-at-scale/high-availability/exercise-1","sidebar":"docs"},{"id":"operate/redis-at-scale/high-availability/exercise-2/index-exercise-2","path":"/operate/redis-at-scale/high-availability/exercise-2","sidebar":"docs"},{"id":"operate/redis-at-scale/high-availability/index-high-availability","path":"/operate/redis-at-scale/high-availability"},{"id":"operate/redis-at-scale/high-availability/introduction/index-introduction","path":"/operate/redis-at-scale/high-availability/introduction","sidebar":"docs"},{"id":"operate/redis-at-scale/high-availability/understanding-sentinels/index-understanding-sentinels","path":"/operate/redis-at-scale/high-availability/understanding-sentinels","sidebar":"docs"},{"id":"operate/redis-at-scale/index-redis-at-scale","path":"/operate/redis-at-scale","sidebar":"docs"},{"id":"operate/redis-at-scale/observability/data-points-in-redis/index-data-points-in-redis","path":"/operate/redis-at-scale/observability/data-points-in-redis","sidebar":"docs"},{"id":"operate/redis-at-scale/observability/exercise-1/index-exercise-1","path":"/operate/redis-at-scale/observability/exercise-1","sidebar":"docs"},{"id":"operate/redis-at-scale/observability/identifying-issues/index-identifying-issues","path":"/operate/redis-at-scale/observability/identifying-issues","sidebar":"docs"},{"id":"operate/redis-at-scale/observability/index-observability","path":"/operate/redis-at-scale/observability"},{"id":"operate/redis-at-scale/observability/introduction/index-introduction","path":"/operate/redis-at-scale/observability/introduction","sidebar":"docs"},{"id":"operate/redis-at-scale/persistence-and-durability/exercise/index-exercise","path":"/operate/redis-at-scale/persistence-and-durability/exercise","sidebar":"docs"},{"id":"operate/redis-at-scale/persistence-and-durability/index-persistence-and-durability","path":"/operate/redis-at-scale/persistence-and-durability"},{"id":"operate/redis-at-scale/persistence-and-durability/introduction/index-introduction","path":"/operate/redis-at-scale/persistence-and-durability/introduction","sidebar":"docs"},{"id":"operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis/index-persistence-options-in-redis","path":"/operate/redis-at-scale/persistence-and-durability/persistence-options-in-redis","sidebar":"docs"},{"id":"operate/redis-at-scale/scalability/clustering-in-redis/index-clustering-in-redis","path":"/operate/redis-at-scale/scalability/lustering-in-redis","sidebar":"docs"},{"id":"operate/redis-at-scale/scalability/exercise-1/index-exercise-1","path":"/operate/redis-at-scale/scalability/exercise-1","sidebar":"docs"},{"id":"operate/redis-at-scale/scalability/index-scalability","path":"/operate/redis-at-scale/scalability"},{"id":"operate/redis-at-scale/scalability/redis-cli-with-redis-cluster/index-redis-cli-with-redis-cluster","path":"/operate/redis-at-scale/scalability/redis-cli-with-redis-cluster","sidebar":"docs"},{"id":"operate/redis-at-scale/scalability/redis-cluster-and-client-libraries/index-redis-cluster-and-client-libraries","path":"/operate/redis-at-scale/scalability/redis-cluster-and-client-libraries","sidebar":"docs"},{"id":"operate/redis-at-scale/talking-to-redis/client-performance-improvements/index-client-performance-improvements","path":"/operate/redis-at-scale/talking-to-redis/client-performance-improvements","sidebar":"docs"},{"id":"operate/redis-at-scale/talking-to-redis/command-line-tool/index-command-line-tool","path":"/operate/redis-at-scale/talking-to-redis/command-line-tool","sidebar":"docs"},{"id":"operate/redis-at-scale/talking-to-redis/configuring-a-redis-server/index-configuring-a-redis-server","path":"/operate/redis-at-scale/talking-to-redis/configuring-a-redis-server","sidebar":"docs"},{"id":"operate/redis-at-scale/talking-to-redis/index-talking-to-redis","path":"/operate/redis-at-scale/talking-to-redis"},{"id":"operate/redis-at-scale/talking-to-redis/initial-tuning/index-initial-tuning","path":"/operate/redis-at-scale/talking-to-redis/initial-tuning","sidebar":"docs"},{"id":"operate/redis-at-scale/talking-to-redis/redis-clients/index-redis-clients","path":"/operate/redis-at-scale/talking-to-redis/redis-clients","sidebar":"docs"},{"id":"operate/redis-at-scale/talking-to-redis/redis-server-overview/index-redis-server-overview","path":"/operate/redis-at-scale/talking-to-redis/redis-server-overview","sidebar":"docs"},{"id":"tools/index-tools","path":"/tools/index-tools"},{"id":"tools/riot/index-riot","path":"/tools/riot"},{"id":"tutorials/redisearch/getting-started/index-redisearch-getting-started","path":"/tutorials/redisearch/getting-started/"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/howtos/quick-start","label":"Quick Start"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var s=n(57529);const c=JSON.parse('{"docusaurusVersion":"2.2.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.2.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.2.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.2.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.2.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.2.0"},"docusaurus-plugin-sass":{"type":"package","name":"docusaurus-plugin-sass","version":"0.2.2"},"docusaurus-plugin-gtm":{"type":"project"}}}'),l={siteConfig:o.default,siteMetadata:c,globalData:a,i18n:i,codeTranslations:s},d=r.createContext(l);function u(e){let{children:t}=e;return r.createElement(d.Provider,{value:l},t)}},44763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(67294),o=n(10412),a=n(35742),i=n(44859);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",height:"50vh",width:"100%",fontSize:"20px"}},r.createElement("h1",null,"This page crashed."),r.createElement("p",null,t.message),r.createElement("button",{type:"button",onClick:n},"Try again"))}function c(e){let{error:t,tryAgain:n}=e;return r.createElement(d,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(a.Z,null,r.createElement("title",null,"Page Error")),r.createElement(i.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const l=e=>r.createElement(c,e);class d extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){o.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??l)(e)}return e??null}}},10412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,o={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},35742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(67294),o=n(70405);function a(e){return r.createElement(o.ql,e)}},39960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>h});var r=n(87462),o=n(67294),a=n(73727),i=n(18780),s=n(52263),c=n(13919),l=n(10412);const d=o.createContext({collectLink:()=>{}});var u=n(44996);function p(e,t){var n;let{isNavLink:p,to:h,href:m,activeClassName:f,isActive:g,"data-noBrokenLinkCheck":b,autoAddBaseUrl:v=!0,...y}=e;const{siteConfig:{trailingSlash:w,baseUrl:x}}=(0,s.Z)(),{withBaseUrl:k}=(0,u.C)(),E=(0,o.useContext)(d),_=(0,o.useRef)(null);(0,o.useImperativeHandle)(t,(()=>_.current));const S=h||m;const T=(0,c.Z)(S),C=null==S?void 0:S.replace("pathname://","");let A=void 0!==C?(P=C,v&&(e=>e.startsWith("/"))(P)?k(P):P):void 0;var P;A&&T&&(A=(0,i.applyTrailingSlash)(A,{trailingSlash:w,baseUrl:x}));const R=(0,o.useRef)(!1),L=p?a.OL:a.rU,N=l.Z.canUseIntersectionObserver,I=(0,o.useRef)(),O=()=>{R.current||null==A||(window.docusaurus.preload(A),R.current=!0)};(0,o.useEffect)((()=>(!N&&T&&null!=A&&window.docusaurus.prefetch(A),()=>{N&&I.current&&I.current.disconnect()})),[I,A,N,T]);const j=(null==(n=A)?void 0:n.startsWith("#"))??!1,D=!A||!T||j;return D||b||E.collectLink(A),D?o.createElement("a",(0,r.Z)({ref:_,href:A},S&&!T&&{target:"_blank",rel:"noopener noreferrer"},y)):o.createElement(L,(0,r.Z)({},y,{onMouseEnter:O,onTouchStart:O,innerRef:e=>{_.current=e,N&&e&&T&&(I.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(I.current.unobserve(e),I.current.disconnect(),null!=A&&window.docusaurus.prefetch(A))}))})),I.current.observe(e))},to:A},p&&{isActive:g,activeClassName:f}))}const h=o.forwardRef(p)},95999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c,I:()=>s});var r=n(67294);function o(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=null==t?void 0:t[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var a=n(57529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return a[t??n]??n??t}function s(e,t){let{message:n,id:r}=e;return o(i({message:n,id:r}),t)}function c(e){let{children:t,id:n,values:a}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const s=i({message:t,id:n});return r.createElement(r.Fragment,null,o(s,a))}},29935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},13919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function o(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>o,b:()=>r})},44996:(e,t,n)=>{"use strict";n.d(t,{C:()=>a,Z:()=>i});var r=n(52263),o=n(13919);function a(){const{siteConfig:{baseUrl:e,url:t}}=(0,r.Z)();return{withBaseUrl:(n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const s=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+s:s}(t,e,n,r)}}function i(e,t){void 0===t&&(t={});const{withBaseUrl:n}=a();return n(e,t)}},52263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(67294),o=n(58940);function a(){return(0,r.useContext)(o._)}},72389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(67294),o=n(98934);function a(){return(0,r.useContext)(o._)}},99670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});function r(e){const t={};return function e(n,r){Object.entries(n).forEach((n=>{let[o,a]=n;const i=r?`${r}.${o}`:o;var s;"object"==typeof(s=a)&&s&&Object.keys(s).length>0?e(a,i):t[i]=a}))}(e),t}},30226:(e,t,n)=>{"use strict";n.d(t,{_:()=>o,z:()=>a});var r=n(67294);const o=r.createContext(null);function a(e){let{children:t,value:n}=e;const a=r.useContext(o),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...null==n?void 0:n.data};return{plugin:t.plugin,data:r}}({parent:a,value:n})),[a,n]);return r.createElement(o.Provider,{value:i},t)}},80143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>f,gA:()=>p,_r:()=>d,Jo:()=>g,zh:()=>u,yW:()=>m,gB:()=>h});var r=n(76775),o=n(52263),a=n(29935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,o.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const s=e=>e.versions.find((e=>e.isLast));function c(e,t){const n=function(e,t){const n=s(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),o=null==n?void 0:n.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:o,alternateDocVersions:o?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(o.id):{}}}const l={},d=()=>i("docusaurus-plugin-content-docs")??l,u=e=>function(e,t,n){void 0===t&&(t=a.m),void 0===n&&(n={});const r=i(e),o=null==r?void 0:r[t];if(!o&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return o}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=d(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const o=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),a=o?{pluginId:o[0],pluginData:o[1]}:void 0;if(!a&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return a}(t,n,e)}function h(e){return u(e).versions}function m(e){const t=u(e);return s(t)}function f(e){const t=u(e),{pathname:n}=(0,r.TH)();return c(t,n)}function g(e){const t=u(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=s(e);return{latestDocSuggestion:c(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},18320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>a});var r=n(74865),o=n.n(r);o().configure({showSpinner:!1});const a={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{o().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){o().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(87410),o=n(36809);!function(e){const{themeConfig:{prism:t}}=o.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(36694)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},39471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(67294);const o="iconExternalLink_nPIU";function a(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:o},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},44859:(e,t,n)=>{"use strict";n.d(t,{Z:()=>ut});var r=n(67294),o=n(86010),a=n(44763),i=n(87462),s=n(76775),c=n(95999),l=n(85936);const d="docusaurus_skipToContent_fallback";function u(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&u(t)}),[]);return(0,l.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&u(e.current)})),{containerRef:e,onClick:n}}const h=(0,c.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function m(e){const t=e.children??h,{containerRef:n,onClick:o}=p();return r.createElement("div",{ref:n,role:"region","aria-label":h},r.createElement("a",(0,i.Z)({},e,{href:`#${d}`,onClick:o}),t))}var f=n(1944),g=n(35281),b=n(19727);const v="skipToContent_fXgn";function y(){return r.createElement(m,{className:v})}var w=n(86668),x=n(59689);function k(e){let{width:t=21,height:n=21,color:o="currentColor",strokeWidth:a=1.2,className:s,...c}=e;return r.createElement("svg",(0,i.Z)({viewBox:"0 0 15 15",width:t,height:n},c),r.createElement("g",{stroke:o,strokeWidth:a},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const E="closeButton_CVFx";function _(e){return r.createElement("button",(0,i.Z)({type:"button","aria-label":(0,c.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,o.Z)("clean-btn close",E,e.className)}),r.createElement(k,{width:14,height:14,strokeWidth:3.1}))}const S="content_knG7";function T(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,i.Z)({},e,{className:(0,o.Z)(S,e.className),dangerouslySetInnerHTML:{__html:n}}))}const C="announcementBar_mb4j",A="announcementBarPlaceholder_vyr4",P="announcementBarClose_gvF7",R="announcementBarContent_xLdY";function L(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,x.nT)();if(!t)return null;const{backgroundColor:o,textColor:a,isCloseable:i}=e;return r.createElement("div",{className:C,style:{backgroundColor:o,color:a},role:"banner"},i&&r.createElement("div",{className:A}),r.createElement(T,{className:R}),i&&r.createElement(_,{onClick:n,className:P}))}var N=n(72961),I=n(12466);var O=n(902),j=n(13102);const D=r.createContext(null);function M(e){let{children:t}=e;const n=function(){const e=(0,N.e)(),t=(0,j.HY)(),[n,o]=(0,r.useState)(!1),a=null!==t.component,i=(0,O.D9)(a);return(0,r.useEffect)((()=>{a&&!i&&o(!0)}),[a,i]),(0,r.useEffect)((()=>{a?e.shown||o(!0):o(!1)}),[e.shown,a]),(0,r.useMemo)((()=>[n,o]),[n])}();return r.createElement(D.Provider,{value:n},t)}function F(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function B(){const e=(0,r.useContext)(D);if(!e)throw new O.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,o=(0,r.useCallback)((()=>n(!1)),[n]),a=(0,j.HY)();return(0,r.useMemo)((()=>({shown:t,hide:o,content:F(a)})),[o,a,t])}function z(e){let{header:t,primaryMenu:n,secondaryMenu:a}=e;const{shown:i}=B();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,o.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},a)))}var U=n(92949),$=n(72389);function q(e){return r.createElement("svg",(0,i.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function H(e){return r.createElement("svg",(0,i.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const Z={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function G(e){let{className:t,value:n,onChange:a}=e;const i=(0,$.Z)(),s=(0,c.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===n?(0,c.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,o.Z)(Z.toggle,t)},r.createElement("button",{className:(0,o.Z)("clean-btn",Z.toggleButton,!i&&Z.toggleButtonDisabled),type:"button",onClick:()=>a("dark"===n?"light":"dark"),disabled:!i,title:s,"aria-label":s,"aria-live":"polite"},r.createElement(q,{className:(0,o.Z)(Z.toggleIcon,Z.lightToggleIcon)}),r.createElement(H,{className:(0,o.Z)(Z.toggleIcon,Z.darkToggleIcon)})))}const V=r.memo(G);function W(e){let{className:t}=e;const n=(0,w.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:a}=(0,U.I)();return n?null:r.createElement(V,{className:t,value:o,onChange:a})}var Y=n(87846);function K(){return r.createElement(Y.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function X(){const e=(0,N.e)();return r.createElement("button",{type:"button","aria-label":(0,c.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(k,{color:"var(--ifm-color-emphasis-600)"}))}function Q(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(K,null),r.createElement(W,{className:"margin-right--md"}),r.createElement(X,null))}var J=n(39960),ee=n(44996),te=n(13919);function ne(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var re=n(39471);function oe(e){let{activeBasePath:t,activeBaseRegex:n,to:o,href:a,label:s,html:c,isDropdownLink:l,prependBaseUrlToHref:d,...u}=e;const p=(0,ee.Z)(o),h=(0,ee.Z)(t),m=(0,ee.Z)(a,{forcePrependBaseUrl:!0}),f=s&&a&&!(0,te.Z)(a),g=c?{dangerouslySetInnerHTML:{__html:c}}:{children:r.createElement(r.Fragment,null,s,f&&r.createElement(re.Z,l&&{width:12,height:12}))};return a?r.createElement(J.Z,(0,i.Z)({href:d?m:a},u,g)):r.createElement(J.Z,(0,i.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?ne(n,t.pathname):t.pathname.startsWith(h)},u,g))}function ae(e){let{className:t,isDropdownItem:n=!1,...a}=e;const s=r.createElement(oe,(0,i.Z)({className:(0,o.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},a));return n?r.createElement("li",null,s):s}function ie(e){let{className:t,isDropdownItem:n,...a}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(oe,(0,i.Z)({className:(0,o.Z)("menu__link",t)},a)))}function se(e){let{mobile:t=!1,position:n,...o}=e;const a=t?ie:ae;return r.createElement(a,(0,i.Z)({},o,{activeClassName:o.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ce=n(86043),le=n(48596),de=n(52263);function ue(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!ne(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function pe(e){let{items:t,position:n,className:a,onClick:s,...c}=e;const l=(0,r.useRef)(null),[d,u]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{l.current&&!l.current.contains(e.target)&&u(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[l]),r.createElement("div",{ref:l,className:(0,o.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":d})},r.createElement(oe,(0,i.Z)({"aria-haspopup":"true","aria-expanded":d,role:"button",href:c.to?void 0:"#",className:(0,o.Z)("navbar__link",a)},c,{onClick:c.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),u(!d))}}),c.children??c.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,n)=>r.createElement(Be,(0,i.Z)({isDropdownItem:!0,onKeyDown:e=>{if(n===t.length-1&&"Tab"===e.key){e.preventDefault(),u(!1);const t=l.current.nextElementSibling;if(t){(t instanceof HTMLAnchorElement?t:t.querySelector("a")).focus()}}},activeClassName:"dropdown__link--active"},e,{key:n}))))))}function he(e){let{items:t,className:n,position:a,onClick:c,...l}=e;const d=function(){const{siteConfig:{baseUrl:e}}=(0,de.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),u=ue(t,d),{collapsed:p,toggleCollapsed:h,setCollapsed:m}=(0,ce.u)({initialState:()=>!u});return(0,r.useEffect)((()=>{u&&m(!u)}),[d,u,m]),r.createElement("li",{className:(0,o.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(oe,(0,i.Z)({role:"button",className:(0,o.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},l,{onClick:e=>{e.preventDefault(),h()}}),l.children??l.label),r.createElement(ce.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(Be,(0,i.Z)({mobile:!0,isDropdownItem:!0,onClick:c,activeClassName:"menu__link--active"},e,{key:t}))))))}function me(e){let{mobile:t=!1,...n}=e;const o=t?he:pe;return r.createElement(o,n)}var fe=n(94711);function ge(e){let{width:t=20,height:n=20,...o}=e;return r.createElement("svg",(0,i.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},o),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const be="iconLanguage_nlXk";function ve(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function ye(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{},r=n.search,o=n.autoSelect,a=void 0!==o&&o,i=n.setValue,s=void 0===i?function(){}:i,c=n.setAttribute,l=void 0===c?function(){}:c,d=n.onUpdate,u=void 0===d?function(){}:d,p=n.onSubmit,h=void 0===p?function(){}:p,m=n.onShow,f=void 0===m?function(){}:m,g=n.onHide,b=void 0===g?function(){}:g,v=n.onLoading,y=void 0===v?function(){}:v,w=n.onLoaded,x=void 0===w?function(){}:w;ve(this,e),we(this,"value",""),we(this,"searchCounter",0),we(this,"results",[]),we(this,"selectedIndex",-1),we(this,"handleInput",(function(e){var n=e.target.value;t.updateResults(n),t.value=n})),we(this,"handleKeyDown",(function(e){var n=e.key;switch(n){case"Up":case"Down":case"ArrowUp":case"ArrowDown":var r="ArrowUp"===n||"Up"===n?t.selectedIndex-1:t.selectedIndex+1;e.preventDefault(),t.handleArrows(r);break;case"Tab":t.selectResult();break;case"Enter":var o=t.results[t.selectedIndex];t.selectResult(),t.onSubmit(o);break;case"Esc":case"Escape":t.hideResults(),t.setValue();break;default:return}})),we(this,"handleFocus",(function(e){var n=e.target.value;t.updateResults(n),t.value=n})),we(this,"handleBlur",(function(){t.hideResults()})),we(this,"handleResultMouseDown",(function(e){e.preventDefault()})),we(this,"handleResultClick",(function(e){var n=e.target,r=ke(n,"[data-result-index]");if(r){t.selectedIndex=parseInt(r.dataset.resultIndex,10);var o=t.results[t.selectedIndex];t.selectResult(),t.onSubmit(o)}})),we(this,"handleArrows",(function(e){var n=t.results.length;t.selectedIndex=(e%n+n)%n,t.onUpdate(t.results,t.selectedIndex)})),we(this,"selectResult",(function(){var e=t.results[t.selectedIndex];e&&t.setValue(e),t.hideResults()})),we(this,"updateResults",(function(e){var n=++t.searchCounter;t.onLoading(),t.search(e).then((function(e){n===t.searchCounter&&(t.results=e,t.onLoaded(),0!==t.results.length?(t.selectedIndex=t.autoSelect?0:-1,t.onUpdate(t.results,t.selectedIndex),t.showResults()):t.hideResults())}))})),we(this,"showResults",(function(){t.setAttribute("aria-expanded",!0),t.onShow()})),we(this,"hideResults",(function(){t.selectedIndex=-1,t.results=[],t.setAttribute("aria-expanded",!1),t.setAttribute("aria-activedescendant",""),t.onUpdate(t.results,t.selectedIndex),t.onHide()})),we(this,"checkSelectedResultVisible",(function(e){var n=e.querySelector('[data-result-index="'.concat(t.selectedIndex,'"]'));if(n){var r=e.getBoundingClientRect(),o=n.getBoundingClientRect();o.topr.bottom&&(e.scrollTop+=o.bottom-r.bottom)}})),this.search=Ee(r)?r:function(e){return Promise.resolve(r(e))},this.autoSelect=a,this.setValue=s,this.setAttribute=l,this.onUpdate=u,this.onSubmit=h,this.onShow=f,this.onHide=b,this.onLoading=y,this.onLoaded=x},Se=0,Te=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return"".concat(e).concat(++Se)},Ce=function(e,t){var n=e.getBoundingClientRect(),r=t.getBoundingClientRect();return n.bottom+r.height>window.innerHeight&&window.innerHeight-n.bottom0?"above":"below"},Ae=function(e,t,n){var r;return function(){var o=this,a=arguments,i=function(){r=null,n||e.apply(o,a)},s=n&&!r;clearTimeout(r),r=setTimeout(i,t),s&&e.apply(o,a)}},Pe=function(){function e(t,n,r){ve(this,e),this.id="".concat(r,"-result-").concat(t),this.class="".concat(r,"-result"),this["data-result-index"]=t,this.tabindex=t,this.role="option",t===n&&(this["aria-selected"]="true")}var t,n,r;return t=e,(n=[{key:"toString",value:function(){var e=this;return Object.keys(this).reduce((function(t,n){return"".concat(t," ").concat(n,'="').concat(e[n],'"')}),"")}}])&&ye(t.prototype,n),r&&ye(t,r),e}();const Re=function e(t){var n=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=r.search,a=r.onSubmit,i=void 0===a?function(){}:a,s=r.onUpdate,c=void 0===s?function(){}:s,l=r.baseClass,d=void 0===l?"redis-sitesearch":l,u=r.autoSelect,p=r.getResultValue,h=void 0===p?function(e){return e}:p,m=r.renderResult,f=r.debounceTime,g=void 0===f?0:f,b=r.zIndex,v=void 0===b?"1":b;ve(this,e),we(this,"expanded",!1),we(this,"loading",!1),we(this,"position",{}),we(this,"resetPosition",!0),we(this,"initialize",(function(){n.root.style.position="relative",n.input.setAttribute("role","combobox"),n.input.setAttribute("redis-sitesearch","off"),n.input.setAttribute("autocapitalize","off"),n.input.setAttribute("autocorrect","off"),n.input.setAttribute("spellcheck","false"),n.input.setAttribute("aria-redis-sitesearch","list"),n.input.setAttribute("aria-haspopup","listbox"),n.input.setAttribute("aria-expanded","false"),n.resultList.setAttribute("role","listbox"),n.resultContainer.style.position="absolute",n.resultContainer.style.zIndex=n.zIndex,n.resultContainer.style.width="100%",n.resultContainer.style.boxSizing="border-box",n.resultList.id||(n.resultList.id=Te("".concat(n.baseClass,"-result-list-"))),n.input.setAttribute("aria-owns",n.resultList.id),document.body.addEventListener("click",n.handleDocumentClick),n.input.addEventListener("keydown",n.handleKeyDown),n.input.addEventListener("input",n.core.handleInput),n.input.addEventListener("focus",n.core.handleFocus),n.resultList.addEventListener("mousedown",n.core.handleResultMouseDown),n.resultList.addEventListener("click",n.core.handleResultClick),n.updateStyle()})),we(this,"updateStyle",(function(){n.root.dataset.expanded=n.expanded,n.root.dataset.loading=n.loading,n.root.dataset.position=n.position,n.resultContainer.style.visibility=n.expanded?"visible":"hidden",n.resultContainer.style.pointerEvents=n.expanded?"auto":"none","below"===n.position?(n.resultContainer.style.bottom=null,n.resultContainer.style.top="100%"):(n.resultContainer.style.top=null,n.resultContainer.style.bottom="100%")})),we(this,"handleKeyDown",(function(e){var t=e.key;switch(t){case"Up":case"Down":case"ArrowUp":case"ArrowDown":var r="ArrowUp"===t||"Up"===t?n.core.selectedIndex-1:n.core.selectedIndex+1;e.preventDefault(),n.core.handleArrows(r);break;case"Tab":n.core.selectResult();break;case"Enter":var o=n.core.results[n.core.selectedIndex];if(!o)return;n.core.selectResult(),n.core.onSubmit(o);break;case"Esc":case"Escape":n.core.hideResults(),n.core.setValue();break;default:return}})),we(this,"setAttribute",(function(e,t){n.input.setAttribute(e,t)})),we(this,"setValue",(function(e){n.input.value=e?n.getResultValue(e):""})),we(this,"renderResult",(function(e,t,r){return"
  • ").concat(n.getResultValue(e,r),"
  • ")})),we(this,"organizeResultsBySection",(function(e){var t={},n=[];return e.forEach((function(e){var r=e.hierarchy[0],o=e.hierarchy.length>1?e.hierarchy[1]:e.hierarchy[0],a=t[r];if(void 0===a){var i={name:r,secondLevelOrder:[o]};i[o]=[e],t[r]=i,n.push(r)}else a.hasOwnProperty(o)||(a[o]=[],a.secondLevelOrder.push(o)),a[o].push(e)})),{topLevelNodes:t,topLevelOrder:n}})),we(this,"handleUpdate",(function(e,t){n.resultList.innerHTML="";var r=-1,o=[],a=n.organizeResultsBySection(e);a.topLevelOrder.forEach((function(e){var i=a.topLevelNodes[e];n.resultList.insertAdjacentHTML("beforeend",'\n
  • \n
    \n '.concat(e,"\n
    \n
  • \n ")),i.secondLevelOrder.forEach((function(e){i[e].forEach((function(e){var a=new Pe(r+=1,t,n.baseClass),i=n.renderResult(e,a,r);"string"==typeof i?n.resultList.insertAdjacentHTML("beforeend",i):n.resultList.insertAdjacentElement("beforeend",i),o.push(e)}))}))})),n.core.results=o,e=o,n.input.setAttribute("aria-activedescendant",t>-1?"".concat(n.baseClass,"-result-").concat(t):""),n.resetPosition&&(n.resetPosition=!1,n.position=Ce(n.input,n.resultList),n.updateStyle()),n.core.checkSelectedResultVisible(n.resultList),n.onUpdate(e,t)})),we(this,"handleShow",(function(){n.expanded=!0,n.updateStyle()})),we(this,"handleHide",(function(){n.expanded=!1,n.resetPosition=!0,n.updateStyle()})),we(this,"handleLoading",(function(){n.loading=!0,n.updateStyle()})),we(this,"handleLoaded",(function(){n.loading=!1,n.updateStyle()})),we(this,"handleDocumentClick",(function(e){e.target&&n.root.contains(e.target)||n.core.hideResults()})),we(this,"updateStyle",(function(){n.root.dataset.expanded=n.expanded,n.root.dataset.loading=n.loading,n.root.dataset.position=n.position,n.resultContainer.style.visibility=n.expanded?"visible":"hidden",n.resultContainer.style.pointerEvents=n.expanded?"auto":"none","below"===n.position?(n.resultContainer.style.bottom=null,n.resultContainer.style.top="100%"):(n.resultContainer.style.top=null,n.resultContainer.style.bottom="100%")})),this.root="string"==typeof t?document.querySelector(t):t,this.input=this.root.querySelector("input"),this.resultList=this.root.querySelector("ul"),this.baseClass=d,this.getResultValue=h,this.onUpdate=c,this.zIndex=v,"function"==typeof m&&(this.renderResult=m);var y=new _e({search:o,autoSelect:u,setValue:this.setValue,setAttribute:this.setAttribute,onUpdate:this.handleUpdate,onSubmit:i,onShow:this.handleShow,onHide:this.handleHide,onLoading:this.handleLoading,onLoaded:this.handleLoaded});g>0&&(y.handleInput=Ae(y.handleInput,g)),this.core=y,this.resultContainer=this.root.querySelector(".redis-sitesearch-result-list-wrapper"),this.resultContainer.style.position="absolute",this.resultContainer.style["z-index"]="1",this.resultContainer.style.width="100%",this.resultContainer.style["box-sizing"]="border-box",this.resultContainer.style.visibility="hidden",this.resultContainer.style["pointer-events"]="none",this.resultContainer.style.bottom="100%",this.redisearchLogo=this.root.querySelector(".redisearch-logo"),this.initialize()};const Le=function(){let e=!1;return(0,r.useEffect)((function(){const t=document.querySelector(".redisearch-logo"),n=document.querySelector("#redis-sitesearch");let r;t&&n&&(e=!0,t.addEventListener("mousedown",(e=>{e.preventDefault()})),new Re("#redis-sitesearch",{debounceTime:2,zIndex:100,search:async e=>{const t=e.trim(),n=`https://search-service.redislabs.com/search?q=${t}*&site=https://developer.redis.com`;if(0===e.length)return[];try{xhr.abort()}catch(a){}r=t;const o=function(e){const t=localStorage.getItem(e);if(!t)return null;const n=JSON.parse(t);return(new Date).getTime()>n.expiry?(localStorage.removeItem(e),null):n.value}(n);if(o)return o;try{const e=await fetch(n);if(!e||!e.ok)return console.error("Error querying search API: ",e),[];const r=await e.json();if(void 0===r||!r)return[];let o;if(r.results.length)o=r.results;else{o=[{title:"No results",section_title:`No results found for '${t.replace(/[&<>"'\/]/g,(function(e){return{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}[e]}))}'`,body:"",hierarchy:[""],url:""}]}return function(e,t,n){const r={value:t,expiry:(new Date).getTime()+n};localStorage.setItem(e,JSON.stringify(r))}(n,o,3e4),o}catch(i){return console.error("Error querying search API: ",i),[]}},renderResult:(e,t)=>{let n="";return""!==e.section_title&&(n=`\n
    \n ${e.section_title}\n
    \n `),`\n
  • \n
    \n
    \n ${e.title}\n
    \n
    \n
    \n ${n}\n
    \n ${e.body}\n
    \n
    \n
  • \n `},getResultValue:()=>"",onSubmit:e=>{e&&(r=encodeURIComponent(r),window.open(`${e.url}?s=${r}`,"_top"))},onUpdate:e=>{const t=document.querySelector(".redisearch-logo");t&&(e.length?t.innerHTML='':t.innerHTML="")}}))}),[e]),r.createElement("div",{id:"redis-sitesearch",className:"redis-sitesearch redis-sitesearch-inline"},r.createElement("input",{className:"redis-sitesearch-input"}),r.createElement("div",{className:"redis-sitesearch-result-list-wrapper"},r.createElement("ul",{className:"redis-sitesearch-result-list"}),r.createElement("div",{className:"redisearch-logo"})))},Ne="searchBox_ZlJk";function Ie(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,o.Z)(n,Ne)},t)}var Oe=n(80143),je=n(53438);var De=n(60373);const Me=e=>e.docs.find((t=>t.id===e.mainDocId));const Fe={default:se,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:o,...a}=e;const{i18n:{currentLocale:l,locales:d,localeConfigs:u}}=(0,de.Z)(),p=(0,fe.l)(),{search:h,hash:m}=(0,s.TH)(),f=[...n,...d.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${h}${m}`;return{label:u[e].label,lang:u[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===l?t?"menu__link--active":"dropdown__link--active":""}})),...o],g=t?(0,c.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):u[l].label;return r.createElement(me,(0,i.Z)({},a,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(ge,{className:be}),g),items:f}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(Ie,{className:n},r.createElement(Le,null))},dropdown:me,html:function(e){let{value:t,className:n,mobile:a=!1,isDropdownItem:i=!1}=e;const s=i?"li":"div";return r.createElement(s,{className:(0,o.Z)({navbar__item:!a&&!i,"menu__list-item":a},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:o,...a}=e;const{activeDoc:s}=(0,Oe.Iw)(o),c=(0,je.vY)(t,o);return null===c?null:r.createElement(se,(0,i.Z)({exact:!0},a,{isActive:()=>(null==s?void 0:s.path)===c.path||!(null==s||!s.sidebar)&&s.sidebar===c.sidebar,label:n??c.id,to:c.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:o,...a}=e;const{activeDoc:s}=(0,Oe.Iw)(o),c=(0,je.oz)(t,o).link;if(!c)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(se,(0,i.Z)({exact:!0},a,{isActive:()=>(null==s?void 0:s.sidebar)===t,label:n??c.label,to:c.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:o,...a}=e;const s=(0,je.lO)(o)[0],c=t??s.label,l=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(s).path;return r.createElement(se,(0,i.Z)({},a,{label:c,to:l}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:o,dropdownItemsBefore:a,dropdownItemsAfter:l,...d}=e;const{search:u,hash:p}=(0,s.TH)(),h=(0,Oe.Iw)(n),m=(0,Oe.gB)(n),{savePreferredVersionName:f}=(0,De.J)(n),g=[...a,...m.map((e=>{const t=h.alternateDocVersions[e.name]??Me(e);return{label:e.label,to:`${t.path}${u}${p}`,isActive:()=>e===h.activeVersion,onClick:()=>f(e.name)}})),...l],b=(0,je.lO)(n)[0],v=t&&g.length>1?(0,c.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&g.length>1?void 0:Me(b).path;return g.length<=1?r.createElement(se,(0,i.Z)({},d,{mobile:t,label:v,to:y,isActive:o?()=>!1:void 0})):r.createElement(me,(0,i.Z)({},d,{mobile:t,label:v,to:y,items:g,isActive:o?()=>!1:void 0}))}};function Be(e){let{type:t,...n}=e;const o=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),a=Fe[o];if(!a)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(a,n)}function ze(){const e=(0,N.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(Be,(0,i.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ue(e){return r.createElement("button",(0,i.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function $e(){const e=0===(0,w.L)().navbar.items.length,t=B();return r.createElement(r.Fragment,null,!e&&r.createElement(Ue,{onClick:()=>t.hide()}),t.content)}function qe(){const e=(0,N.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(z,{header:r.createElement(Q,null),primaryMenu:r.createElement(ze,null),secondaryMenu:r.createElement($e,null)}):null}const He="navbarHideable_m1mJ",Ze="navbarHidden_jGov";function Ge(e){return r.createElement("div",(0,i.Z)({role:"presentation"},e,{className:(0,o.Z)("navbar-sidebar__backdrop",e.className)}))}function Ve(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:a}}=(0,w.L)(),i=(0,N.e)(),{navbarRef:s,isNavbarVisible:c}=function(e){const[t,n]=(0,r.useState)(e),o=(0,r.useRef)(!1),a=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(a.current=e.getBoundingClientRect().height)}),[]);return(0,I.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=s?n(!1):i+l{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return o.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:s,className:(0,o.Z)("navbar","navbar--fixed-top",n&&[He,!c&&Ze],{"navbar--dark":"dark"===a,"navbar--primary":"primary"===a,"navbar-sidebar--show":i.shown})},t,r.createElement(Ge,{onClick:i.toggle}),r.createElement(qe,null))}function We(e){let{width:t=30,height:n=30,className:o,...a}=e;return r.createElement("svg",(0,i.Z)({className:o,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},a),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Ye(){const{toggle:e,shown:t}=(0,N.e)();return r.createElement("button",{onClick:e,"aria-label":(0,c.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(We,null))}const Ke="colorModeToggle_DEke";function Xe(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Be,(0,i.Z)({},e,{key:t})))))}function Qe(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Je(){const e=(0,N.e)(),t=(0,w.L)().navbar.items,[n,o]=function(e){function t(e){return"left"===(e.position??"right")}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return r.createElement(Qe,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Ye,null),r.createElement(K,null),r.createElement(Xe,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Xe,{items:o}),r.createElement(W,{className:Ke}),!a&&r.createElement(Ie,null,r.createElement(Le,null)))})}function et(){return r.createElement(Ve,null,r.createElement(Je,null))}const tt="footerLogoLink_fGS1",nt=e=>{let{color:t="#465282",...n}=e;return r.createElement("svg",(0,i.Z)({width:"785",height:"158",xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink"},n),r.createElement("defs",null,r.createElement("path",{d:"M786.344 392.459c-41.822 22.164-258.313 110.84-305.056 135.477-46.742 24.637-72.163 23.812-108.246 6.57-36.082-17.24-267.334-111.664-309.156-131.377-41.822-19.713-42.642-33.657-1.64-49.271C103.25 338.265 332.86 247.94 381.243 229.875c48.383-18.065 65.604-18.065 106.605-2.473 41.003 15.614 256.674 100.996 297.676 115.785 41.002 14.791 42.642 27.912.82 49.273v-.001z",id:"a"}),r.createElement("mask",{id:"b",maskContentUnits:"userSpaceOnUse",maskUnits:"objectBoundingBox",x:"0",y:"0",width:"785",height:"331",fill:"#fff"},r.createElement("use",{xlinkHref:"#a"}))),r.createElement("use",{mask:"url(#b)",xlinkHref:"#a",transform:"translate(-32 -216)",stroke:t,strokeWidth:"4",fill:"none",fillRule:"evenodd",strokeDasharray:"3.637"}))};function rt(e){let{to:t,href:n,label:o,prependBaseUrlToHref:a,...s}=e;const c=(0,ee.Z)(t),l=(0,ee.Z)(n,{forcePrependBaseUrl:!0});return r.createElement(J.Z,(0,i.Z)({className:"footer__link-item"},n?{target:"_blank",rel:"noopener noreferrer",href:a?l:n}:{to:c},s),o)}const ot=e=>{let{url:t,alt:n}=e;return r.createElement("img",{loading:"lazy",className:"footer__logo",alt:n,src:t})};const at=function(){const{footer:e}=(0,w.L)(),{copyright:t,links:n=[],logo:a={src:void 0,alt:""}}=e??{},i=(0,ee.Z)(a.src);return e?r.createElement("footer",{className:(0,o.Z)("footer",{"footer--dark":"dark"===e.style})},r.createElement("div",{className:"container"},r.createElement(nt,{className:"shape"}),r.createElement("img",{src:(0,ee.Z)("/img/code-2.png"),className:"code",alt:""}),r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--3"},a&&a.src&&r.createElement("div",{className:"footer__logo-ctr"},r.createElement("span",{className:"footer__logo-tagline"},"Made with by"),a.href?r.createElement("a",{href:a.href,target:"_blank",rel:"noopener",className:tt},r.createElement(ot,{alt:a.alt??"",url:i})):r.createElement(ot,{alt:a.alt??"",url:i}))),r.createElement("div",{className:"col col--9"},n&&n.length>0&&r.createElement("div",{className:"row footer__links"},n.map(((e,t)=>r.createElement("div",{key:t,className:"col col--4 footer__col"},null!=e.title?r.createElement("h4",{className:"footer__title"},e.title):null,null!=e.items&&Array.isArray(e.items)&&e.items.length>0?r.createElement("ul",{className:"footer__items"},e.items.map(((e,t)=>e.html?r.createElement("li",{key:t,className:"footer__item",dangerouslySetInnerHTML:{__html:e.html}}):r.createElement("li",{key:e.href||e.to,className:"footer__item"},r.createElement(rt,e))))):null)))))),t?r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}}):null)):null};var it=n(7094);const st=(0,O.Qc)([U.S,x.pl,it.z,I.OC,De.L5,f.VC,function(e){let{children:t}=e;return r.createElement(j.n2,null,r.createElement(N.M,null,r.createElement(M,null,t)))}]);function ct(e){let{children:t}=e;return r.createElement(st,null,t)}function lt(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("p",null,t.message),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},r.createElement(c.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}const dt="mainWrapper_z2l0";function ut(e){const{children:t,noFooter:n,wrapperClassName:i,title:s,description:c}=e;return(0,b.t)(),r.createElement(ct,null,r.createElement(f.d,{title:s,description:c}),r.createElement(y,null),r.createElement(L,null),r.createElement(et,null),r.createElement("div",{id:d,className:(0,o.Z)(g.k.wrapper.main,dt,i)},r.createElement(a.Z,{fallback:e=>r.createElement(lt,e)},t)),!n&&r.createElement(at,null))}},87846:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(87462),o=n(67294),a=n(39960),i=n(44996),s=n(52263),c=n(86668),l=n(86010),d=n(72389),u=n(92949);const p={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function h(e){const t=(0,d.Z)(),{colorMode:n}=(0,u.I)(),{sources:a,className:i,alt:s,...c}=e,h=t?"dark"===n?["dark"]:["light"]:["light","dark"];return o.createElement(o.Fragment,null,h.map((e=>o.createElement("img",(0,r.Z)({key:e,src:a[e],alt:s,className:(0,l.Z)(p.themedImage,p[`themedImage--${e}`],i)},c)))))}function m(e){let{logo:t,alt:n,imageClassName:r}=e;const a={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},s=o.createElement(h,{className:t.className,sources:a,height:t.height,width:t.width,alt:n,style:t.style});return r?o.createElement("div",{className:r},s):s}function f(e){const{siteConfig:{title:t}}=(0,s.Z)(),{navbar:{title:n,logo:l}}=(0,c.L)(),{imageClassName:d,titleClassName:u,...p}=e,h=(0,i.Z)((null==l?void 0:l.href)||"/"),f=n?"":t,g=(null==l?void 0:l.alt)??f;return o.createElement(a.Z,(0,r.Z)({to:h},p,(null==l?void 0:l.target)&&{target:l.target}),l&&o.createElement(m,{logo:l,alt:g,imageClassName:d}),null!=n&&o.createElement("b",{className:u},n))}},90197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(67294),o=n(35742);function a(e){let{locale:t,version:n,tag:a}=e;const i=t;return r.createElement(o.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),a&&r.createElement("meta",{name:"docusaurus_tag",content:a}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),a&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:a}))}},86043:(e,t,n)=>{"use strict";n.d(t,{u:()=>i,z:()=>m});var r=n(87462),o=n(67294),a=n(10412);function i(e){let{initialState:t}=e;const[n,r]=(0,o.useState)(t??!1),a=(0,o.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:a}}const s={display:"none",overflow:"hidden",height:"0px"},c={display:"block",overflow:"visible",height:"auto"};function l(e,t){const n=t?s:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const a=(0,o.useRef)(!1);(0,o.useEffect)((()=>{const e=t.current;function o(){const t=e.scrollHeight,n=(null==r?void 0:r.duration)??function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${(null==r?void 0:r.easing)??"ease-in-out"}`,height:`${t}px`}}function i(){const t=o();e.style.transition=t.transition,e.style.height=t.height}if(!a.current)return l(e,n),void(a.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(i(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{i()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function u(e){if(!a.Z.canUseDOM)return e?s:c}function p(e){let{as:t="div",collapsed:n,children:r,animation:a,onCollapseTransitionEnd:i,className:s,disableSSRStyle:c}=e;const p=(0,o.useRef)(null);return d({collapsibleRef:p,collapsed:n,animation:a}),o.createElement(t,{ref:p,style:c?void 0:u(n),onTransitionEnd:e=>{"height"===e.propertyName&&(l(p.current,n),null==i||i(n))},className:s},r)}function h(e){let{collapsed:t,...n}=e;const[a,i]=(0,o.useState)(!t),[s,c]=(0,o.useState)(t);return(0,o.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,o.useLayoutEffect)((()=>{a&&c(t)}),[a,t]),a?o.createElement(p,(0,r.Z)({},n,{collapsed:s})):null}function m(e){let{lazy:t,...n}=e;const r=t?h:p;return o.createElement(r,n)}},59689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>h});var r=n(67294),o=n(72389),a=n(50012),i=n(902),s=n(86668);const c=(0,a.W)("docusaurus.announcement.dismiss"),l=(0,a.W)("docusaurus.announcement.id"),d=()=>"true"===c.get(),u=e=>c.set(String(e)),p=r.createContext(null);function h(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,s.L)(),t=(0,o.Z)(),[n,a]=(0,r.useState)((()=>!!t&&d()));(0,r.useEffect)((()=>{a(d())}),[]);const i=(0,r.useCallback)((()=>{u(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=l.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;l.set(t),r&&u(!1),!r&&d()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(p.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(p);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},92949:(e,t,n)=>{"use strict";n.d(t,{I:()=>g,S:()=>f});var r=n(67294),o=n(10412),a=n(902),i=n(50012),s=n(86668);const c=r.createContext(void 0),l="theme",d=(0,i.W)(l),u="light",p="dark",h=e=>e===p?p:u;function m(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,s.L)(),[a,i]=(0,r.useState)((e=>o.Z.canUseDOM?h(document.documentElement.getAttribute("data-theme")):h(e))(e));(0,r.useEffect)((()=>{t&&d.del()}),[t]);const c=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:o=!0}=r;t?(i(t),o&&(e=>{d.set(h(e))})(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?p:u:e),d.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",h(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==l)return;const t=d.get();null!==t&&c(h(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,c]);const m=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||m.current?m.current=window.matchMedia("print").matches:c(null)};return e.addListener(r),()=>e.removeListener(r)}),[c,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:c,get isDarkTheme(){return a===p},setLightTheme(){c(u)},setDarkTheme(){c(p)}})),[a,c])}function f(e){let{children:t}=e;const n=m();return r.createElement(c.Provider,{value:n},t)}function g(){const e=(0,r.useContext)(c);if(null==e)throw new a.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},60373:(e,t,n)=>{"use strict";n.d(t,{J:()=>y,L5:()=>b});var r=n(67294),o=n(80143),a=n(29935),i=n(86668),s=n(53438),c=n(902),l=n(50012);const d=e=>`docs-preferred-version-${e}`,u=(e,t,n)=>{(0,l.W)(d(e),{persistence:t}).set(n)},p=(e,t)=>(0,l.W)(d(e),{persistence:t}).get(),h=(e,t)=>{(0,l.W)(d(e),{persistence:t}).del()};const m=r.createContext(null);function f(){const e=(0,o._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[a,s]=(0,r.useState)((()=>(e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}]))))(n)));(0,r.useEffect)((()=>{s(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function o(e){const t=p(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(h(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,o(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[a,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){u(e,t,n),s((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=f();return r.createElement(m.Provider,{value:n},t)}function b(e){let{children:t}=e;return s.cE?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function v(){const e=(0,r.useContext)(m);if(!e)throw new c.i6("DocsPreferredVersionContextProvider");return e}function y(e){void 0===e&&(e=a.m);const t=(0,o.zh)(e),[n,i]=v(),{preferredVersionName:s}=n[e];return{preferredVersion:t.versions.find((e=>e.name===s))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>c,b:()=>s});var r=n(67294),o=n(902);const a=Symbol("EmptyContext"),i=r.createContext(a);function s(e){let{children:t,name:n,items:o}=e;const a=(0,r.useMemo)((()=>n&&o?{name:n,items:o}:null),[n,o]);return r.createElement(i.Provider,{value:a},t)}function c(){const e=(0,r.useContext)(i);if(e===a)throw new o.i6("DocsSidebarProvider");return e}},72961:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>h});var r=n(67294),o=n(13102),a=n(87524),i=n(76775),s=n(902);function c(e){!function(e){const t=(0,i.k6)(),n=(0,s.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var l=n(86668);const d=r.createContext(void 0);function u(){const e=function(){const e=(0,o.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,a.i)(),n=!e&&"mobile"===t,[i,s]=(0,r.useState)(!1);c((()=>{if(i)return s(!1),!1}));const d=(0,r.useCallback)((()=>{s((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&s(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:d,shown:i})),[e,n,d,i])}function p(e){let{children:t}=e;const n=u();return r.createElement(d.Provider,{value:n},t)}function h(){const e=r.useContext(d);if(void 0===e)throw new s.i6("NavbarMobileSidebarProvider");return e}},13102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>s,Zo:()=>c,n2:()=>i});var r=n(67294),o=n(902);const a=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(a.Provider,{value:n},t)}function s(){const e=(0,r.useContext)(a);if(!e)throw new o.i6("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const i=(0,r.useContext)(a);if(!i)throw new o.i6("NavbarSecondaryMenuContentProvider");const[,s]=i,c=(0,o.Ql)(n);return(0,r.useEffect)((()=>{s({component:t,props:c})}),[s,t,c]),(0,r.useEffect)((()=>()=>s({component:null,props:null})),[s]),null}},7094:(e,t,n)=>{"use strict";n.d(t,{U:()=>l,z:()=>c});var r=n(67294),o=n(50012),a=n(902);const i="docusaurus.tab.",s=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,o.W)(`docusaurus.tab.${e}`).set(t)}),[]);(0,r.useEffect)((()=>{try{const e={};(0,o._)().forEach((t=>{if(t.startsWith(i)){const n=t.substring(i.length);e[n]=(0,o.W)(t).get()}})),t(e)}catch(e){console.error(e)}}),[]);const a=(0,r.useCallback)(((e,r)=>{t((t=>({...t,[e]:r}))),n(e,r)}),[n]);return(0,r.useMemo)((()=>({tabGroupChoices:e,setTabGroupChoices:a})),[e,a])}();return r.createElement(s.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(s);if(null==e)throw new a.i6("TabGroupChoiceProvider");return e}},19727:(e,t,n)=>{"use strict";n.d(t,{h:()=>o,t:()=>a});var r=n(67294);const o="navigation-with-keyboard";function a(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},87524:(e,t,n)=>{"use strict";n.d(t,{i:()=>l});var r=n(67294),o=n(10412);const a="desktop",i="mobile",s="ssr";function c(){return o.Z.canUseDOM?window.innerWidth>996?a:i:s}function l(){const[e,t]=(0,r.useState)((()=>c()));return(0,r.useEffect)((()=>{function e(){t(c())}return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(undefined)}}),[]),e}},35281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},53438:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>p,_F:()=>m,cE:()=>u,hI:()=>w,lO:()=>b,oz:()=>v,s1:()=>g,vY:()=>y});var r=n(67294),o=n(76775),a=n(18790),i=n(80143),s=n(60373),c=n(1116),l=n(67392),d=n(48596);const u=!!i._r;function p(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=p(t);if(e)return e}}}const h=(e,t)=>void 0!==e&&(0,d.Mg)(e,t);function m(e,t){return"link"===e.type?h(e.href,t):"category"===e.type&&(h(e.href,t)||((e,t)=>e.some((e=>m(e,t))))(e.items,t))}function f(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const o=[];return function e(t){for(const a of t)if("category"===a.type&&((0,d.Mg)(a.href,n)||e(a.items))||"link"===a.type&&(0,d.Mg)(a.href,n)){return r&&"category"!==a.type||o.unshift(a),!0}return!1}(t),o}function g(){var e;const t=(0,c.V)(),{pathname:n}=(0,o.TH)();return!1!==(null==(e=(0,i.gA)())?void 0:e.pluginData.breadcrumbs)&&t?f({sidebarItems:t.items,pathname:n}):null}function b(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,s.J)(e),o=(0,i.yW)(e);return(0,r.useMemo)((()=>(0,l.j)([t,n,o].filter(Boolean))),[t,n,o])}function v(e,t){const n=b(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\n Available sidebar ids are:\n - ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function y(e,t){const n=b(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`DocNavbarItem: couldn't find any doc with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${(0,l.j)(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function w(e){let{route:t,versionMetadata:n}=e;const r=(0,o.TH)(),i=t.routes,s=i.find((e=>(0,o.LX)(r.pathname,e)));if(!s)return null;const c=s.sidebar,l=c?n.docsSidebars[c]:void 0;return{docElement:(0,a.H)(i),sidebarName:c,sidebarItems:l}}},67392:(e,t,n)=>{"use strict";function r(e,t){return void 0===t&&(t=(e,t)=>e===t),e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function o(e){return Array.from(new Set(e))}n.d(t,{j:()=>o,l:()=>r})},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>d,VC:()=>h});var r=n(67294),o=n(86010),a=n(35742),i=n(30226);function s(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var c=n(44996),l=n(52263);function d(e){let{title:t,description:n,keywords:o,image:i,children:s}=e;const d=function(e){const{siteConfig:t}=(0,l.Z)(),{title:n,titleDelimiter:r}=t;return null!=e&&e.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:u}=(0,c.C)(),p=i?u(i,{absolute:!0}):void 0;return r.createElement(a.Z,null,t&&r.createElement("title",null,d),t&&r.createElement("meta",{property:"og:title",content:d}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),o&&r.createElement("meta",{name:"keywords",content:Array.isArray(o)?o.join(","):o}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),s)}const u=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const i=r.useContext(u),s=(0,o.Z)(i,t);return r.createElement(u.Provider,{value:s},r.createElement(a.Z,null,r.createElement("html",{className:s})),n)}function h(e){let{children:t}=e;const n=s(),a=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,o.Z)(a,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>l,Ql:()=>c,i6:()=>s,zX:()=>a});var r=n(67294);const o=n(10412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function a(e){const t=(0,r.useRef)(e);return o((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return o((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){var n,r,o;super(),this.name="ReactContextError",this.message=`Hook ${(null==(n=this.stack)||null==(r=n.split("\n")[1])||null==(o=r.match(/at (?:\w+\.)?(?\w+)/))?void 0:o.groups.name)??""} is called outside the <${e}>. ${t??""}`}}function c(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function l(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},48596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>s});var r=n(67294),o=n(723),a=n(52263);function i(e,t){const n=e=>{var t;return null==(t=!e||e.endsWith("/")?e:`${e}/`)?void 0:t.toLowerCase()};return n(e)===n(t)}function s(){const{baseUrl:e}=(0,a.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function o(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(o).flatMap((e=>e.routes??[])))}(n)}({routes:o.Z,baseUrl:e})),[e])}},12466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>h,OC:()=>c,RF:()=>u,o5:()=>p});var r=n(67294),o=n(10412),a=n(72389),i=n(902);const s=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(s.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(s);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const d=()=>o.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function u(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=l(),o=(0,r.useRef)(d()),a=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=d();a(e,o.current),o.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[a,n,...t])}function p(){const e=l(),t=function(){const e=(0,r.useRef)({elem:null,top:0}),t=(0,r.useCallback)((t=>{e.current={elem:t,top:t.getBoundingClientRect().top}}),[]),n=(0,r.useCallback)((()=>{const{current:{elem:t,top:n}}=e;if(!t)return{restored:!1};const r=t.getBoundingClientRect().top-n;return r&&window.scrollBy({left:0,top:r}),e.current={elem:null,top:0},{restored:0!==r}}),[]);return(0,r.useMemo)((()=>({save:t,restore:n})),[n,t])}(),n=(0,r.useRef)(void 0),o=(0,r.useCallback)((r=>{t.save(r),e.disableScrollEvents(),n.current=()=>{const{restored:r}=t.restore();if(n.current=void 0,r){const t=()=>{e.enableScrollEvents(),window.removeEventListener("scroll",t)};window.addEventListener("scroll",t)}else e.enableScrollEvents()}}),[e,t]);return(0,r.useLayoutEffect)((()=>{null==n.current||n.current()})),{blockElementScrollPositionUntilNextRender:o}}function h(){const e=(0,r.useRef)(null),t=(0,a.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const o=document.documentElement.scrollTop;(n&&o>e||!n&&ot&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>null==e.current?void 0:e.current()}}},43320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>o});n(52263);const r="default";function o(e,t){return`docs-${e}-${t}`}},50012:(e,t,n)=>{"use strict";n.d(t,{W:()=>s,_:()=>c});const r="localStorage";function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,a||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),a=!0),null}var t}let a=!1;const i={get:()=>null,set:()=>{},del:()=>{}};function s(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t}}(e);const n=o(null==t?void 0:t.persistence);return null===n?i:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{n.setItem(e,t)}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{n.removeItem(e)}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}}}}function c(e){void 0===e&&(e=r);const t=o(e);if(!t)return[];const n=[];for(let r=0;r{"use strict";n.d(t,{l:()=>a});var r=n(52263),o=n(76775);function a(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:a}}=(0,r.Z)(),{pathname:i}=(0,o.TH)(),s=a===n?e:e.replace(`/${a}/`,"/"),c=i.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:o}=e;return`${o?t:""}${function(e){return e===n?`${s}`:`${s}${e}/`}(r)}${c}`}}}},85936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(67294),o=n(76775),a=n(902);function i(e){const t=(0,o.TH)(),n=(0,a.D9)(t),i=(0,a.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},86668:(e,t,n)=>{"use strict";n.d(t,{L:()=>o});var r=n(52263);function o(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[o]=e.split(/[#?]/),a="/"===o||o===r?o:(i=o,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(o,a)}},18780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="post-content";var o=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(o).default}})},86010:(e,t,n)=>{"use strict";function r(e){var t,n,o="";if("string"==typeof e||"number"==typeof e)o+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;to});const o=function(){for(var e,t,n=0,o="";n{"use strict";n.d(t,{lX:()=>w,q_:()=>T,ob:()=>h,PP:()=>A,Ep:()=>p});var r=n(87462);function o(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,o=e.length;r=0;p--){var h=i[p];"."===h?a(i,p):".."===h?(a(i,p),u++):u&&(a(i,p),u--)}if(!l)for(;u--;u)i.unshift("..");!l||""===i[0]||i[0]&&o(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var s=n(2177);function c(e){return"/"===e.charAt(0)?e:"/"+e}function l(e){return"/"===e.charAt(0)?e.substr(1):e}function d(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function u(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,o=t||"/";return n&&"?"!==n&&(o+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(o+="#"===r.charAt(0)?r:"#"+r),o}function h(e,t,n,o){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",o=t.indexOf("#");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf("?");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=(0,r.Z)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(s){throw s instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):s}return n&&(a.key=n),o?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname="/"),a}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,o):n.push(o),u({action:r,location:o,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",o=h(e,t,f(),w.location);d.confirmTransitionTo(o,r,n,(function(e){e&&(w.entries[w.index]=o,u({action:r,location:o}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(59864),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},s={};function c(e){return r.isMemo(e)?i:s[e.$$typeof]||o}s[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[r.Memo]=i;var l=Object.defineProperty,d=Object.getOwnPropertyNames,u=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,h=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var o=h(n);o&&o!==m&&e(t,o,r)}var i=d(n);u&&(i=i.concat(u(n)));for(var s=c(t),f=c(n),g=0;g{"use strict";e.exports=function(e,t,n,r,o,a,i,s){if(!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,o,a,i,s],d=0;(c=new Error(t.replace(/%s/g,(function(){return l[d++]})))).name="Invariant Violation"}throw c.framesToPop=1,c}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},93878:(e,t,n)=>{"use strict";n.r(t)},32497:(e,t,n)=>{"use strict";n.r(t)},74865:function(e,t,n){var r,o;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
    '};function o(e,t,n){return en?n:e}function a(e){return 100*(-1+e)}function i(e,t,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+a(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+a(e)+"%,0)"}:{"margin-left":a(e)+"%"}).transition="all "+t+"ms "+n,o}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=o(e,r.minimum,1),n.status=1===e?null:e;var a=n.render(!t),l=a.querySelector(r.barSelector),d=r.speed,u=r.easing;return a.offsetWidth,s((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),c(l,i(e,d,u)),1===e?(c(a,{transition:"none",opacity:1}),a.offsetWidth,setTimeout((function(){c(a,{transition:"all "+d+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),d)}),d)):setTimeout(t,d)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*o(Math.random()*t,.1,.95)),t=o(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");d(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var o,i=t.querySelector(r.barSelector),s=e?"-100":a(n.status||0),l=document.querySelector(r.parent);return c(i,{transition:"all 0 linear",transform:"translate3d("+s+"%,0,0)"}),r.showSpinner||(o=t.querySelector(r.spinnerSelector))&&h(o),l!=document.body&&d(l,"nprogress-custom-parent"),l.appendChild(t),t},n.remove=function(){u(document.documentElement,"nprogress-busy"),u(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&h(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var s=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),c=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,o=e.length,a=t.charAt(0).toUpperCase()+t.slice(1);o--;)if((r=e[o]+a)in n)return r;return t}function o(e){return e=n(e),t[e]||(t[e]=r(e))}function a(e,t,n){t=o(t),e.style[t]=n}return function(e,t){var n,r,o=arguments;if(2==o.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&a(e,n,r);else a(e,o[1],o[2])}}();function l(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function d(e,t){var n=p(e),r=n+t;l(n,t)||(e.className=r.substring(1))}function u(e,t){var n,r=p(e);l(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function h(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},27418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function o(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(o){return!1}}()?Object.assign:function(e,a){for(var i,s,c=o(e),l=1;l{var r=n(5826);e.exports=h,e.exports.parse=a,e.exports.compile=function(e,t){return s(a(e,t),t)},e.exports.tokensToFunction=s,e.exports.tokensToRegExp=p;var o=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function a(e,t){for(var n,r=[],a=0,i=0,s="",d=t&&t.delimiter||"/";null!=(n=o.exec(e));){var u=n[0],p=n[1],h=n.index;if(s+=e.slice(i,h),i=h+u.length,p)s+=p[1];else{var m=e[i],f=n[2],g=n[3],b=n[4],v=n[5],y=n[6],w=n[7];s&&(r.push(s),s="");var x=null!=f&&null!=m&&m!==f,k="+"===y||"*"===y,E="?"===y||"*"===y,_=n[2]||d,S=b||v;r.push({name:g||a++,prefix:f||"",delimiter:_,optional:E,repeat:k,partial:x,asterisk:!!w,pattern:S?l(S):w?".*":"[^"+c(_)+"]+?"})}}return i{"use strict";n.d(t,{Z:()=>a});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof o?new o(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=u.reach);E+=k.value.length,k=k.next){var _=k.value;if(t.length>e.length)return;if(!(_ instanceof o)){var S,T=1;if(v){if(!(S=a(x,E,e,b))||S.index>=e.length)break;var C=S.index,A=S.index+S[0].length,P=E;for(P+=k.value.length;C>=P;)P+=(k=k.next).value.length;if(E=P-=k.value.length,k.value instanceof o)continue;for(var R=k;R!==t.tail&&(Pu.reach&&(u.reach=O);var j=k.prev;if(N&&(j=c(t,j,N),E+=N.length),l(t,j,T),k=c(t,j,new o(p,g?r.tokenize(L,g):L,y,L)),I&&c(t,k,I),T>1){var D={cause:p+","+m,reach:O};i(e,t,n,k.prev,E,D),u&&D.reach>u.reach&&(u.reach=D.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function c(e,t,n){var r=t.next,o={value:n,prev:t,next:r};return t.next=o,r.prev=o,e.length++,o}function l(e,t,n){for(var r=t.next,o=0;o"+a.content+""},r}(),o=r;r.default=r,o.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},o.languages.markup.tag.inside["attr-value"].inside.entity=o.languages.markup.entity,o.languages.markup.doctype.inside["internal-subset"].inside=o.languages.markup,o.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(o.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:o.languages[t]},n.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:o.languages[t]};var a={};a[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},o.languages.insertBefore("markup","cdata",a)}}),Object.defineProperty(o.languages.markup.tag,"addAttribute",{value:function(e,t){o.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:o.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),o.languages.html=o.languages.markup,o.languages.mathml=o.languages.markup,o.languages.svg=o.languages.markup,o.languages.xml=o.languages.extend("markup",{}),o.languages.ssml=o.languages.xml,o.languages.atom=o.languages.xml,o.languages.rss=o.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var o=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],a=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},o.languages.c=o.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),o.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),o.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},o.languages.c.string],char:o.languages.c.char,comment:o.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:o.languages.c}}}}),o.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete o.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(o),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(o),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},o={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:o,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:o})}(o),o.languages.javascript=o.languages.extend("clike",{"class-name":[o.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),o.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,o.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:o.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:o.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:o.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:o.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:o.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),o.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:o.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),o.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),o.languages.markup&&(o.languages.markup.tag.addInlined("script","javascript"),o.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),o.languages.js=o.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(o),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",o=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return"(?:"+o+"|"+a+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(a),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(o),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(//g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,o=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),a=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+o+a+"(?:"+o+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+o+a+")(?:"+o+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+o+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+o+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\b|\*\*(?:(?!\*)|\*(?:(?!\*))+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)|__(?:(?!_))+__)+_\b|\*(?:(?!\*)|\*\*(?:(?!\*))+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\]))+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n",quot:'"'},c=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(o),o.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:o.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},o.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n0)){var s=p(/^\{$/,/^\}$/);if(-1===s)continue;for(var c=n;c=0&&h(l,"variable-input")}}}}function d(e){return t[n+e]}function u(e,t){t=t||0;for(var n=0;n?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,o=r.inside["interpolation-punctuation"],a=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function s(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function c(t,n,r){var o={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",o),o.tokens=e.tokenize(o.code,o.grammar),e.hooks.run("after-tokenize",o),o.tokens}function l(t){var n={};n["interpolation-punctuation"]=o;var a=e.tokenize(t,n);if(3===a.length){var i=[1,1];i.push.apply(i,c(a[1],e.languages.javascript,"javascript")),a.splice.apply(a,i)}return new e.Token("interpolation",a,r.alias,t)}function d(t,n,r){var o=e.tokenize(t,{interpolation:{pattern:RegExp(a),lookbehind:!0}}),i=0,d={},u=c(o.map((function(e){if("string"==typeof e)return e;for(var n,o=e.content;-1!==t.indexOf(n=s(i++,r)););return d[n]=o,n})).join(""),n,r),p=Object.keys(d);return i=0,function e(t){for(var n=0;n=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var o=p[i],a="string"==typeof r?r:r.content,s=a.indexOf(o);if(-1!==s){++i;var c=a.substring(0,s),u=l(d[o]),h=a.substring(s+o.length),m=[];if(c&&m.push(c),m.push(u),h){var f=[h];e(f),m.push.apply(m,f)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(u),new e.Token(r,u,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var u={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in u&&function t(n){for(var r=0,o=n.length;r]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(o),function(e){function t(e,t){return RegExp(e.replace(//g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:(?:\s*,\s*(?:\*\s*as\s+|\{[^{}]*\}))?|\*\s*as\s+|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r*\.{3}(?:[^{}]|)*\})/.source;function a(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return o})),RegExp(e,t)}o=a(o).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=a(/<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:a(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:a(/=/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},s=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===i(o.content[0].content[1])&&n.pop():"/>"===o.content[o.content.length-1].content||n.push({tagName:i(o.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===o.type&&"{"===o.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===o.type&&"}"===o.content?n[n.length-1].openedBraces--:a=!0),(a||"string"==typeof o)&&n.length>0&&0===n[n.length-1].openedBraces){var c=i(o);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(c=i(t[r-1])+c,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",c,null,c)}o.content&&"string"!=typeof o.content&&s(o.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||s(e.tokens)}))}(o),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],o=[];/^\w+$/.test(n)||o.push(/\w+/.exec(n)[0]),"diff"===n&&o.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:o,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(o),o.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},o.languages.go=o.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),o.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete o.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,s=i.length;-1!==n.code.indexOf(o=t(r,s));)++s;return i[s]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(s){for(var c=0;c=a.length);c++){var l=s[c];if("string"==typeof l||l.content&&"string"==typeof l.content){var d=a[o],u=n.tokenStack[d],p="string"==typeof l?l:l.content,h=t(r,d),m=p.indexOf(h);if(m>-1){++o;var f=p.substring(0,m),g=new e.Token(r,e.tokenize(u,n.grammar),"language-"+r,u),b=p.substring(m+h.length),v=[];f&&v.push.apply(v,i([f])),v.push(g),b&&v.push.apply(v,i([b])),"string"==typeof l?s.splice.apply(s,[c,1].concat(v)):l.content=v}}else l.content&&i(l.content)}return s}(n.tokens)}}}})}(o),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(o),o.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},o.languages.webmanifest=o.languages.json,o.languages.less=o.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),o.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),o.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},o.languages.objectivec=o.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete o.languages.objectivec["class-name"],o.languages.objc=o.languages.objectivec,o.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},o.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},o.languages.python["string-interpolation"].inside.interpolation.inside.rest=o.languages.python,o.languages.py=o.languages.python,o.languages.reason=o.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),o.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete o.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(o),o.languages.scss=o.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),o.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),o.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),o.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),o.languages.scss.atrule.inside.rest=o.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(o),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(o),o.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const a=o},79016:()=>{!function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,r){return RegExp(t(e,n),r||"")}function r(e,t){for(var n=0;n>/g,(function(){return"(?:"+e+")"}));return e.replace(/<>/g,"[^\\s\\S]")}var o="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",a="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",s="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function c(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var l=c(a),d=RegExp(c(o+" "+a+" "+i+" "+s)),u=c(a+" "+i+" "+s),p=c(o+" "+a+" "+s),h=r(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),m=r(/\((?:[^()]|<>)*\)/.source,2),f=/@?\b[A-Za-z_]\w*\b/.source,g=t(/<<0>>(?:\s*<<1>>)?/.source,[f,h]),b=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[u,g]),v=/\[\s*(?:,\s*)*\]/.source,y=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[b,v]),w=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[h,m,v]),x=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[w]),k=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[x,b,v]),E={keyword:d,punctuation:/[<>()?,.:[\]]/},_=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,S=/"(?:\\.|[^\\"\r\n])*"/.source,T=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[T]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[S]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[b]),lookbehind:!0,inside:E},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[f,k]),lookbehind:!0,inside:E},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[f]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[l,g]),lookbehind:!0,inside:E},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[b]),lookbehind:!0,inside:E},{pattern:n(/(\bwhere\s+)<<0>>/.source,[f]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[y]),lookbehind:!0,inside:E},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[k,p,f]),inside:E}],keyword:d,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[f]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[f]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[m]),lookbehind:!0,alias:"class-name",inside:E},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[k,b]),inside:E,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[k]),lookbehind:!0,inside:E,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[f,h]),inside:{function:n(/^<<0>>/.source,[f]),generic:{pattern:RegExp(h),alias:"class-name",inside:E}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[l,g,f,k,d.source,m,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[g,m]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:d,"class-name":{pattern:RegExp(k),greedy:!0,inside:E},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var C=S+"|"+_,A=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[C]),P=r(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[A]),2),R=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,L=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[b,P]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[R,L]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[R]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[P]),inside:e.languages.csharp},"class-name":{pattern:RegExp(b),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var N=/:[^}\r\n]+/.source,I=r(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[A]),2),O=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[I,N]),j=r(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[C]),2),D=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[j,N]);function M(t,r){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[r,N]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[O]),lookbehind:!0,greedy:!0,inside:M(O,I)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[D]),lookbehind:!0,greedy:!0,inside:M(D,j)}],char:{pattern:RegExp(_),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(Prism)},68805:()=>{Prism.languages.elixir={doc:{pattern:/@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,inside:{attribute:/^@\w+/,string:/['"][\s\S]+/}},comment:{pattern:/#.*/,greedy:!0},regex:{pattern:/~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,greedy:!0},string:[{pattern:/~[cCsSwW](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|#\{[^}]+\}|#(?!\{)|[^#\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[csa]?/,greedy:!0,inside:{}},{pattern:/("""|''')[\s\S]*?\1/,greedy:!0,inside:{}},{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{}}],atom:{pattern:/(^|[^:]):\w+/,lookbehind:!0,alias:"symbol"},module:{pattern:/\b[A-Z]\w*\b/,alias:"class-name"},"attr-name":/\b\w+\??:(?!:)/,argument:{pattern:/(^|[^&])&\d+/,lookbehind:!0,alias:"variable"},attribute:{pattern:/@\w+/,alias:"variable"},function:/\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d))/,number:/\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,keyword:/\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\b/,boolean:/\b(?:false|nil|true)\b/,operator:[/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,{pattern:/([^<])<(?!<)/,lookbehind:!0},{pattern:/([^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,%\[\]{}()]/},Prism.languages.elixir.string.forEach((function(e){e.inside={interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:Prism.languages.elixir}}}}))},40485:()=>{!function(e){var t={pattern:/((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:null}}};e.languages.groovy=e.languages.extend("clike",{string:{pattern:/'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,greedy:!0},keyword:/\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,number:/\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,operator:{pattern:/(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),e.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment",greedy:!0},"interpolation-string":{pattern:/"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}}}),e.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(?:and|cleanup|expect|given|setup|then|when|where):/}),e.languages.insertBefore("groovy","function",{annotation:{pattern:/(^|[^.])@\w+/,lookbehind:!0,alias:"punctuation"}}),t.inside.expression.inside=e.languages.groovy}(Prism)},52503:()=>{!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,r={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[r,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:r.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:r.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":r,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:r.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:r.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},99945:()=>{!function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],r=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,o=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,a=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:r,operator:o,punctuation:a};var i={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},s=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:i}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:i}}];e.languages.insertBefore("php","variable",{string:s,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:s,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:r,operator:o,punctuation:a}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){if(/<\?/.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)}})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(Prism)},59385:()=>{!function(e){e.languages.ruby=e.languages.extend("clike",{comment:{pattern:/#.*|^=begin\s[\s\S]*?^=end/m,greedy:!0},"class-name":{pattern:/(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,operator:/\.{2,3}|&\.|===||[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,punctuation:/[(){}[\].,;]/}),e.languages.insertBefore("ruby","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}});var t={pattern:/((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,lookbehind:!0,inside:{content:{pattern:/^(#\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.ruby},delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"}}};delete e.languages.ruby.function;var n="(?:"+[/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source].join("|")+")",r=/(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;e.languages.insertBefore("ruby","keyword",{"regex-literal":[{pattern:RegExp(/%r/.source+n+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:[{pattern:RegExp(/(^|[^:]):/.source+r),lookbehind:!0,greedy:!0},{pattern:RegExp(/([\r\n{(,][ \t]*)/.source+r+/(?=:(?!:))/.source),lookbehind:!0,greedy:!0}],"method-definition":{pattern:/(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,lookbehind:!0,inside:{function:/\b\w+$/,keyword:/^self\b/,"class-name":/^\w+/,punctuation:/\./}}}),e.languages.insertBefore("ruby","string",{"string-literal":[{pattern:RegExp(/%[qQiIwWs]?/.source+n),greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?/}},interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?'|'$/}},string:/[\s\S]+/}}],"command-literal":[{pattern:RegExp(/%x/.source+n),greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}},{pattern:/`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}}]}),delete e.languages.ruby.string,e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,constant:/\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/}),e.languages.rb=e.languages.ruby}(Prism)},70767:()=>{!function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|)*\*\//.source,n=0;n<2;n++)t=t.replace(//g,(function(){return t}));t=t.replace(//g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(Prism)},35266:()=>{Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/}},96836:()=>{!function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(Prism)},36694:(e,t,n)=>{var r={"./prism-csharp":79016,"./prism-elixir":68805,"./prism-groovy":40485,"./prism-java":52503,"./prism-php":99945,"./prism-ruby":59385,"./prism-rust":70767,"./prism-sql":35266,"./prism-typescript":96836};function o(e){var t=a(e);return n(t)}function a(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}o.keys=function(){return Object.keys(r)},o.resolve=a,e.exports=o,o.id=36694},92703:(e,t,n)=>{"use strict";var r=n(50414);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var s=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},45697:(e,t,n)=>{e.exports=n(92703)()},50414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},64448:(e,t,n)=>{"use strict";var r=n(67294),o=n(27418),a=n(63840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n