From 34077a2441ca8d3aef57122844e2b69599e597fc Mon Sep 17 00:00:00 2001 From: ZIO-gRPC Docs Date: Sun, 20 Aug 2023 18:32:19 +0000 Subject: [PATCH] Deploy website - based on bcb647c755facd1e11374ca56a3302321ef1962c --- 404.html | 10 ++-- ...c73f9.fe32af45.js => 215c73f9.f6cda901.js} | 2 +- assets/js/21f2ac89.082666c8.js | 1 + assets/js/21f2ac89.3322f6b4.js | 1 - assets/js/2ed64f4e.3dc9e2e0.js | 1 - assets/js/2ed64f4e.b357c219.js | 1 + assets/js/3a2a6d86.51f62376.js | 1 + assets/js/3a2a6d86.7d5c9a66.js | 1 - assets/js/47bf511f.5545cdc7.js | 1 + assets/js/47bf511f.b6adbf1f.js | 1 - ...69c2c.17650cab.js => 52069c2c.786775a4.js} | 2 +- assets/js/5ee1189a.d6dd4826.js | 1 - assets/js/5ee1189a.fc66384a.js | 1 + assets/js/77b5bd74.31a58916.js | 1 - assets/js/77b5bd74.aee6d68d.js | 1 + assets/js/8ff58b1b.5baad39a.js | 1 - assets/js/8ff58b1b.8c852a58.js | 1 + ...50c67.e62a200d.js => 90150c67.4c39be07.js} | 2 +- assets/js/935f2afb.4336e142.js | 1 + assets/js/935f2afb.ff856733.js | 1 - assets/js/9c997467.3158f533.js | 1 - assets/js/9c997467.ce02b66a.js | 1 + assets/js/a9f25167.0fee2468.js | 1 - assets/js/a9f25167.3bb07c1b.js | 1 + assets/js/aa547a5c.ea208cf8.js | 1 + assets/js/aa547a5c.ee528685.js | 1 - ...b6cad.e0cec153.js => ab3b6cad.f83e1208.js} | 2 +- assets/js/b484f81c.24e0b9b6.js | 1 - assets/js/b484f81c.de35fec2.js | 1 + assets/js/b5b67730.601a1665.js | 1 - assets/js/b5b67730.fcf6fa54.js | 1 + assets/js/c445b332.ab06c409.js | 1 + assets/js/c445b332.c8b07d76.js | 1 - assets/js/cdb862af.68f06069.js | 1 - assets/js/cdb862af.fcfcd51f.js | 1 + assets/js/d066d984.08a9c1ac.js | 1 - assets/js/d066d984.f490eff7.js | 1 + assets/js/e367d32b.9c3c66f7.js | 1 - assets/js/e367d32b.a1038f3c.js | 1 + ...e2072.8c4d8ec3.js => fbee2072.aa9261f1.js} | 2 +- assets/js/main.fb3865ed.js | 2 + ...CENSE.txt => main.fb3865ed.js.LICENSE.txt} | 0 assets/js/main.fd9a46fd.js | 2 - assets/js/runtime~main.6bfc54b5.js | 1 - assets/js/runtime~main.93e81000.js | 1 + docs/0.5.x/backpressure/index.html | 20 ++++++++ docs/{next => 0.5.x}/basics/index.html | 50 +++++++++---------- docs/0.5.x/context/index.html | 26 ++++++++++ docs/0.5.x/deadlines/index.html | 30 +++++++++++ docs/0.5.x/decorating/index.html | 22 ++++++++ docs/0.5.x/generated-code/index.html | 21 ++++++++ docs/0.5.x/index.html | 18 +++++++ docs/0.5.x/installation/index.html | 21 ++++++++ docs/0.5.x/quickstart/index.html | 18 +++++++ docs/0.5.x/scala.js/index.html | 19 +++++++ docs/backpressure/index.html | 16 +++--- docs/basics/index.html | 50 +++++++++---------- docs/context/index.html | 28 +++++------ docs/deadlines/index.html | 26 +++++----- docs/decorating/index.html | 19 ++++--- docs/generated-code/index.html | 21 ++++---- docs/index.html | 14 +++--- docs/installation/index.html | 18 +++---- docs/next/backpressure/index.html | 20 -------- docs/next/context/index.html | 26 ---------- docs/next/deadlines/index.html | 30 ----------- docs/next/decorating/index.html | 21 -------- docs/next/generated-code/index.html | 24 --------- docs/next/index.html | 18 ------- docs/next/installation/index.html | 21 -------- docs/next/quickstart/index.html | 18 ------- docs/next/scala.js/index.html | 19 ------- docs/quickstart/index.html | 14 +++--- docs/scala.js/index.html | 16 +++--- index.html | 10 ++-- sitemap.xml | 2 +- 76 files changed, 368 insertions(+), 368 deletions(-) rename assets/js/{215c73f9.fe32af45.js => 215c73f9.f6cda901.js} (75%) create mode 100644 assets/js/21f2ac89.082666c8.js delete mode 100644 assets/js/21f2ac89.3322f6b4.js delete mode 100644 assets/js/2ed64f4e.3dc9e2e0.js create mode 100644 assets/js/2ed64f4e.b357c219.js create mode 100644 assets/js/3a2a6d86.51f62376.js delete mode 100644 assets/js/3a2a6d86.7d5c9a66.js create mode 100644 assets/js/47bf511f.5545cdc7.js delete mode 100644 assets/js/47bf511f.b6adbf1f.js rename assets/js/{52069c2c.17650cab.js => 52069c2c.786775a4.js} (69%) delete mode 100644 assets/js/5ee1189a.d6dd4826.js create mode 100644 assets/js/5ee1189a.fc66384a.js delete mode 100644 assets/js/77b5bd74.31a58916.js create mode 100644 assets/js/77b5bd74.aee6d68d.js delete mode 100644 assets/js/8ff58b1b.5baad39a.js create mode 100644 assets/js/8ff58b1b.8c852a58.js rename assets/js/{90150c67.e62a200d.js => 90150c67.4c39be07.js} (77%) create mode 100644 assets/js/935f2afb.4336e142.js delete mode 100644 assets/js/935f2afb.ff856733.js delete mode 100644 assets/js/9c997467.3158f533.js create mode 100644 assets/js/9c997467.ce02b66a.js delete mode 100644 assets/js/a9f25167.0fee2468.js create mode 100644 assets/js/a9f25167.3bb07c1b.js create mode 100644 assets/js/aa547a5c.ea208cf8.js delete mode 100644 assets/js/aa547a5c.ee528685.js rename assets/js/{ab3b6cad.e0cec153.js => ab3b6cad.f83e1208.js} (52%) delete mode 100644 assets/js/b484f81c.24e0b9b6.js create mode 100644 assets/js/b484f81c.de35fec2.js delete mode 100644 assets/js/b5b67730.601a1665.js create mode 100644 assets/js/b5b67730.fcf6fa54.js create mode 100644 assets/js/c445b332.ab06c409.js delete mode 100644 assets/js/c445b332.c8b07d76.js delete mode 100644 assets/js/cdb862af.68f06069.js create mode 100644 assets/js/cdb862af.fcfcd51f.js delete mode 100644 assets/js/d066d984.08a9c1ac.js create mode 100644 assets/js/d066d984.f490eff7.js delete mode 100644 assets/js/e367d32b.9c3c66f7.js create mode 100644 assets/js/e367d32b.a1038f3c.js rename assets/js/{fbee2072.8c4d8ec3.js => fbee2072.aa9261f1.js} (69%) create mode 100644 assets/js/main.fb3865ed.js rename assets/js/{main.fd9a46fd.js.LICENSE.txt => main.fb3865ed.js.LICENSE.txt} (100%) delete mode 100644 assets/js/main.fd9a46fd.js delete mode 100644 assets/js/runtime~main.6bfc54b5.js create mode 100644 assets/js/runtime~main.93e81000.js create mode 100644 docs/0.5.x/backpressure/index.html rename docs/{next => 0.5.x}/basics/index.html (50%) create mode 100644 docs/0.5.x/context/index.html create mode 100644 docs/0.5.x/deadlines/index.html create mode 100644 docs/0.5.x/decorating/index.html create mode 100644 docs/0.5.x/generated-code/index.html create mode 100644 docs/0.5.x/index.html create mode 100644 docs/0.5.x/installation/index.html create mode 100644 docs/0.5.x/quickstart/index.html create mode 100644 docs/0.5.x/scala.js/index.html delete mode 100644 docs/next/backpressure/index.html delete mode 100644 docs/next/context/index.html delete mode 100644 docs/next/deadlines/index.html delete mode 100644 docs/next/decorating/index.html delete mode 100644 docs/next/generated-code/index.html delete mode 100644 docs/next/index.html delete mode 100644 docs/next/installation/index.html delete mode 100644 docs/next/quickstart/index.html delete mode 100644 docs/next/scala.js/index.html diff --git a/404.html b/404.html index d33a7fdd8..3637a6d17 100644 --- a/404.html +++ b/404.html @@ -6,13 +6,13 @@ Page Not Found | ZIO gRPC - - + +
-
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + \ No newline at end of file diff --git a/assets/js/215c73f9.fe32af45.js b/assets/js/215c73f9.f6cda901.js similarity index 75% rename from assets/js/215c73f9.fe32af45.js rename to assets/js/215c73f9.f6cda901.js index 76a00ad9d..18814eb05 100644 --- a/assets/js/215c73f9.fe32af45.js +++ b/assets/js/215c73f9.f6cda901.js @@ -1 +1 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[764],{3905:function(e,t,r){r.d(t,{Zo:function(){return u},kt:function(){return m}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),m=o,d=f["".concat(s,".").concat(m)]||f[m]||p[m]||a;return r?n.createElement(d,i(i({ref:t},u),{},{components:r})):n.createElement(d,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),m=o,d=f["".concat(s,".").concat(m)]||f[m]||p[m]||a;return r?n.createElement(d,i(i({ref:t},u),{},{components:r})):n.createElement(d,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var l=2;l=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 l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(h,o(o({ref:t},p),{},{components:n})):a.createElement(h,o({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var u=2;u Status.NOT_FOUND)\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def findFeature(point: Point): Option[Feature] =\n features.find(f => f.getLocation == point && f.name.nonEmpty)\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method takes the request (of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), and returns a ZIO\neffect that represents the work of computing the response. The value that is returned represents\na suspended effect: nothing actually happens until ZIO runtime\nultimately runs the effect. The type of the effect is ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO[ZEnv, Status, Feature]")," which means\nit is a computation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"can fail with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"Status")," (this type comes from grpc-java and represents a gRPC status code)."),(0,r.kt)("li",{parentName:"ul"},"can succeed with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"Feature"),"."),(0,r.kt)("li",{parentName:"ul"},"requires an environment of type ",(0,r.kt)("inlineCode",{parentName:"li"},"ZEnv")," to run.")),(0,r.kt)("p",null,"In this case, our effect is built on top of a pure function ",(0,r.kt)("inlineCode",{parentName:"p"},"findFeature")," that returns ",(0,r.kt)("inlineCode",{parentName:"p"},"Some(feature)"),"\nif there is a feature in the database that corresponds to the given point, or ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," otherwise."),(0,r.kt)("p",null,"We use ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO.fromOption")," to turn the ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Feature]")," into an effect of type ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[Option[Nothing], Feature]"),"\nwhich means that it can either succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," or fail with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Nothing]")," (the only possible value of this type is ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," since there are no instances of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Nothing"),"). We\nthen use ",(0,r.kt)("inlineCode",{parentName:"p"},"mapError")," to map the case of an error to gRPC's ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND")," status."),(0,r.kt)("h3",{id:"server-side-streaming-rpc"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next let's look at one of our streaming RPCs. ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures")," is a server-side\nstreaming RPC, so we need to send back multiple ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s to our client."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def listFeatures(request: Rectangle): ZStream[ZEnv, Status, Feature] = {\n val left = request.getLo.longitude min request.getHi.longitude\n val right = request.getLo.longitude max request.getHi.longitude\n val top = request.getLo.latitude max request.getHi.latitude\n val bottom = request.getLo.latitude min request.getHi.latitude\n\n ZStream.fromIterable(\n features.filter { feature =>\n val lat = feature.getLocation.latitude\n val lon = feature.getLocation.longitude\n lon >= left && lon <= right && lat >= bottom && lat <= top\n }\n )\n}\n")),(0,r.kt)("p",null,"Like the simple RPC, this method gets a request object (the ",(0,r.kt)("inlineCode",{parentName:"p"},"Rectangle")," in which\nour client wants to find ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s) and returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream[ZEnv, Status, Feature]"),", which represents an effectful stream that can produce, provided an environment of type\n",(0,r.kt)("inlineCode",{parentName:"p"},"ZEnv")," zero or more elements of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," and fail with a value of type of ",(0,r.kt)("inlineCode",{parentName:"p"},"Status"),"."),(0,r.kt)("p",null," This time, the stream does not need the environment and can not ever fail (since\nour database is a constant in the same process!)"),(0,r.kt)("p",null," We build the stream from a Scala collection we build by filtering through the features\nsequence. ZIO gRPC takes over streaming the response to the client when the stream\ngets executed."),(0,r.kt)("h3",{id:"client-side-streaming-rpc"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now let's look at something a little more complicated: the client-side streaming\nmethod ",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute()"),", where we get a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s from the client and\nreturn a single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," with information about their trip once the stream finishes."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def recordRoute(\n request: zio.stream.Stream[Status, Point]\n): ZIO[Clock, Status, RouteSummary] = {\n // Zips each element with the previous element, initially accompanied by None.\n request.zipWithPrevious\n .fold(RouteSummary()) {\n case (summary, (maybePrevPoint, currentPoint)) =>\n // Compute the next status based on the current status.\n summary.copy(\n pointCount = summary.pointCount + 1,\n featureCount =\n summary.featureCount + (if (findFeature(currentPoint).isDefined) 1\n else 0),\n distance = summary.distance + maybePrevPoint\n .map(calcDistance(_, currentPoint))\n .getOrElse(0)\n )\n }\n .timed // returns a new effect that times the execution\n .map {\n case (duration, summary) =>\n summary.copy(elapsedTime = (duration.toMillis / 1000).toInt)\n }\n}\n")),(0,r.kt)("p",null,"Here, our method gets a stream that is produced by the client. As you can see\nfrom the signature of this method, our goal would be to turn this stream into an\neffect that results in a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," contains the number of points, number of features on the trip, total distance passed, and the time it took. As this summary can be built iteratively we use fold, which takes the summary and new input to compute the next summary. Since we are\nadding up the distance between successive pair of points, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithPrevious"),"\nthat gives us a pair ",(0,r.kt)("inlineCode",{parentName:"p"},"(Option[Point], Point)")," where the left element represents the previous element in the stream (which is initially None)."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fold")," method gives us a ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[Status, RouteSummary]"),". Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"timed")," method we are getting a new ZIO effect that upon success gives us the a tuple ",(0,r.kt)("inlineCode",{parentName:"p"},"(zio.duration.Duration, RouteSummary)")," where the duration represents the time it took to process\nthe effect thus far. We then use ",(0,r.kt)("inlineCode",{parentName:"p"},"map")," to turn it back to a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," that contains the elapsed time in seconds."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def routeChat(\n request: zio.stream.Stream[Status, RouteNote]\n): ZStream[ZEnv, Status, RouteNote] =\n request.flatMap { note =>\n // By using flatMap, we can map each RouteNote we receive to a stream with\n // the existing RouteNotes for that location, and those sub-streams are going\n // to get concatenated.\n // We start from an effect that updates the map with the new RouteNote,\n // and returns the notes associated with the location just before the update.\n val updateMapEffect: UIO[List[RouteNote]] =\n routeNotesRef.modify { routeNotes =>\n val messages = routeNotes.getOrElse(note.getLocation, Nil)\n (messages, routeNotes.updated(note.getLocation, note :: messages))\n }\n // We create a stream from the effect.\n ZStream.fromIterableM(updateMapEffect)\n }\n")),(0,r.kt)("p",null,"As with our client-side streaming example, we are getting a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s, except this time we are also returning a stream of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s. Although each side will always get the other's messages in the\norder they were written, both the client and server can read and write in any\norder \u2014 the streams operate completely independently."),(0,r.kt)("p",null,"In this example, we are using ",(0,r.kt)("inlineCode",{parentName:"p"},"flatMap")," on the incoming stream to map each input to a new\neffectful stream representing the notes that are available in that location. We are using ",(0,r.kt)("inlineCode",{parentName:"p"},"Ref#modify")," to mutate the collection of notes in the given location and return the list of notes available just prior to the update."),(0,r.kt)("h2",{id:"starting-the-server"},"Starting the server"),(0,r.kt)("p",null,"Once we've implemented all our methods, we also need to start up a gRPC server\nso that clients can actually use our service. The following snippet shows how we\ndo this for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide")," service:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'object RouteGuideServer extends ServerMain {\n override def port: Int = 8980\n\n val featuresDatabase = JsonFormat.fromJsonString[FeatureDatabase](\n Source.fromResource("route_guide_db.json").mkString\n )\n\n val createRouteGuide = for {\n routeNotes <- Ref.make(Map.empty[Point, List[RouteNote]])\n } yield new RouteGuideService(featuresDatabase.feature, routeNotes)\n\n def services: ServiceList[zio.ZEnv] =\n ServiceList.addM(createRouteGuide)\n}\n')),(0,r.kt)("p",null,"ZIO gRPC provides a base trait to quickly set up gRPC services with zero boilerplate."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"We override the port we are going to use (default is 9000)"),(0,r.kt)("li",{parentName:"ol"},"Create an effect that constructs an instance of our service (we need an effectful construction since\nour service constructor takes a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.Ref"),")"),(0,r.kt)("li",{parentName:"ol"},"Override ",(0,r.kt)("inlineCode",{parentName:"li"},"def services")," to return a ",(0,r.kt)("inlineCode",{parentName:"li"},"ServiceList")," that contains our service.")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," is meant to be used for simple applications. If you need to do more in your initialization, you can take a look at the source code of ",(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," and customize."),(0,r.kt)("h2",{id:"creating-the-client"},"Creating the client"),(0,r.kt)("p",null,"In this section, we'll look at creating a client for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide"),"\nservice. You can see our complete example client code in\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/scalapb/zio-grpc/blob/master/examples/src/main/scala/zio_grpc/examples/routeguide/RouteGuideClientApp.scala"},"RouteGuideClientApp.scala"),"."),(0,r.kt)("h3",{id:"instantiating-a-client"},"Instantiating a client"),(0,r.kt)("p",null,"To call service methods, we first need to create a client. There are two patterns\nto work with clients:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.managed")," to instantiate a client inside a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.ZManaged"),". Then through calling its ",(0,r.kt)("inlineCode",{parentName:"li"},"use")," method, the client can be accessed and method can be called on it."),(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.live")," to create a ",(0,r.kt)("inlineCode",{parentName:"li"},"ZLayer")," that can be used to provide a client as a singleton to our program through the environment. In that case, throughout the program we use accessor methods, defined statically in ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient")," that expect the client to be available in the environment.")),(0,r.kt)("p",null,"Throughout this tutorial, we will follow the second pattern. We create a ",(0,r.kt)("inlineCode",{parentName:"p"},"Layer")," that can provide a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val clientLayer: Layer[Throwable, RouteGuideClient] =\n RouteGuideClient.live(\n ZManagedChannel(\n ManagedChannelBuilder.forAddress("localhost", 8980).usePlaintext()\n )\n )\n')),(0,r.kt)("h3",{id:"calling-service-methods"},"Calling service methods"),(0,r.kt)("p",null,"Now let's look at how we call our service methods."),(0,r.kt)("p",null,"As described above, ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," contains accessor methods for each RPC\nthat return an effect or a stream that needs a client in the environment to be ran:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def getFeature(req: Point):\n ZIO[RouteGuideClient, Status, Feature]\n\ndef listFeatures(req: Rectangle):\n ZStream[RouteGuideClient, Status, Feature]\n\ndef recordRoute[R0](req: ZStream[R0, Status, Point]):\n ZIO[RouteGuideClient with R0, Status, RouteSummary]\n\ndef routeChat[R0](req: ZStream[R0, Status, RouteNote]):\n ZStream[RouteGuideClient with R0, Status, RouteNote]\n")),(0,r.kt)("h3",{id:"simple-rpc-1"},"Simple RPC"),(0,r.kt)("p",null,"Calling the simple RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"GetFeature")," on the static accessor stub is as\nstraightforward as instantiating a local effect:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def getFeature(\n lat: Int,\n lng: Int\n): ZIO[RouteGuideClient with Console, Status, Unit] =\n (for {\n f <- RouteGuideClient.getFeature(Point(lat, lng))\n _ <- putStrLn(s"""Found feature called "${f.name}".""")\n } yield ()).catchSome {\n case status if status == Status.NOT_FOUND =>\n putStrLn(s"Feature not found: ${status.toString()}")\n }\n')),(0,r.kt)("p",null,"We create and populate a request protocol buffer object (in our case\n",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), pass it to the ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method on our accessor, and get\nback an effect that needs a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," environment. We chain\nthe response with a call to ",(0,r.kt)("inlineCode",{parentName:"p"},"putStrLn")," to print the result on the console,\nand we catch the ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND"),' response and print an error. All other errors\nare not handled at this level and will "bubble up" up to the program\'s ',(0,r.kt)("inlineCode",{parentName:"p"},"exitCode")," handler."),(0,r.kt)("h3",{id:"server-side-streaming-rpc-1"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next, let's look at a server-side streaming call to ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures"),", which\nreturns a stream of geographical ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'_ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach {\n case (feature, index) =>\n putStrLn(s"Result #${index + 1}: $feature")\n }\n')),(0,r.kt)("p",null,"Now ",(0,r.kt)("inlineCode",{parentName:"p"},"listFeatures")," returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream"),". We use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithIndex")," to get a stream\nwhere each of the original elements are accompanied with a zero-based index. We turn\nthis stream into a single effect that processes the entire stream by calling ",(0,r.kt)("inlineCode",{parentName:"p"},"foreach"),"\nand providing it with a function that maps each element into an effect. In this case,\nthe effect prints the feature."),(0,r.kt)("h3",{id:"client-side-streaming-rpc-1"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now for something a little more complicated: the client-side streaming method\n",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute"),", where we send a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s to the server and get back\na single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def recordRoute(numPoints: Int) =\n for {\n summary <- RouteGuideClient.recordRoute(\n ZStream\n .repeatEffect(\n nextIntBetween(0, features.size).map(features(_).getLocation)\n )\n .tap(p => putStrLn(s"Visiting (${p.latitude}, ${p.longitude})"))\n .schedule(Schedule.spaced(300.millis))\n .take(numPoints)\n )\n _ <- putStrLn(\n s"Finished trip with ${summary.pointCount} points. " +\n s"Passed ${summary.featureCount} features. " +\n s"Travelled ${summary.distance} meters. " +\n s"It took ${summary.elapsedTime} seconds."\n )\n } yield ()\n')),(0,r.kt)("p",null,"Here, we pass into ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute")," an effectful stream that randomly picks an element from the ",(0,r.kt)("inlineCode",{parentName:"p"},"features")," collection (a constant), and insert random delay between elements."),(0,r.kt)("p",null,"Like all the other accessor methods it's worth noting that no side effect happens upon calling ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute"),". The method returns immediately giving us an effect that represents sending this stream to the server. When the effect ultimately run it can succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," once the entire stream has been sent to the server."),(0,r.kt)("p",null,"In this example, we chain to this effect an effect to print the summary to the console."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc-1"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val routeChat =\n for {\n res <-\n RouteGuideClient\n .routeChat(\n ZStream(\n RouteNote(\n location = Some(Point(0, 0)),\n message = "First message"\n ),\n RouteNote(\n location = Some(Point(0, 10_000_000)),\n message = "Second Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 0)),\n message = "Third Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 10_000_000)),\n message = "Four Message"\n )\n ).tap { note =>\n putStrLn(\n s"""Sending message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n )\n }\n )\n .foreach { note =>\n putStrLn(\n s"""Got message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n )\n }\n } yield ()\n')),(0,r.kt)("p",null,"In this method, we both get and return a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\nRouteNotes. Here both streams execute independently at the same time. Although each side will always\nget the other's messages in the order they were written, both the client and\nserver can read and write in any order \u2014 the streams operate completely\nindependently."),(0,r.kt)("h3",{id:"providing-the-client-layer-into-the-application-logic"},"Providing the client layer into the application logic"),(0,r.kt)("p",null,"All the effects we created were dependent on a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," available in the environment. We earlier instantiated a ",(0,r.kt)("inlineCode",{parentName:"p"},"clientLayer"),", so we can provide it to our application logic at the top-level (the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val myAppLogic =\n for {\n // Looking for a valid feature\n _ <- getFeature(409146138, -746188906)\n // Looking for a missing feature\n _ <- getFeature(0, 0)\n\n // Calls listFeatures with a rectangle of interest. Prints\n // each response feature as it arrives.\n // start: listFeatures\n _ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach {\n case (feature, index) =>\n putStrLn(s"Result #${index + 1}: $feature")\n }\n // end: listFeatures\n\n _ <- recordRoute(10)\n\n _ <- routeChat\n } yield ()\n\nfinal def run(args: List[String]) =\n myAppLogic.provideCustomLayer(clientLayer).exitCode\n')),(0,r.kt)("h2",{id:"try-it-out"},"Try it out!"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Run the server:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideServer"\n'))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"From another terminal, run the client:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideClientApp"\n')))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},'This document, "ZIO gRPC: Basics Tutorial", is a derivative of ',(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/docs/languages/java/basics/"},'"gRPC ',"\u2013",' Basics Tutorial"')," by ",(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/"},"gRPC Authors"),", used under ",(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0"),'. "ZIO gRPC: Basics Tutorial" is licensed under ',(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0")," by Nadav Samet.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/21f2ac89.3322f6b4.js b/assets/js/21f2ac89.3322f6b4.js deleted file mode 100644 index 22bffd422..000000000 --- a/assets/js/21f2ac89.3322f6b4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[399],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function 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 l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(h,o(o({ref:t},p),{},{components:n})):a.createElement(h,o({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var u=2;u Status.NOT_FOUND)\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def findFeature(point: Point): Option[Feature] =\n features.find(f => f.getLocation == point && f.name.nonEmpty)\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method takes the request (of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), and returns a ZIO\neffect that represents the work of computing the response. The value that is returned represents\na suspended effect: nothing actually happens until ZIO runtime\nultimately runs the effect. The type of the effect is ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO[ZEnv, Status, Feature]")," which means\nit is a computation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"can fail with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"Status")," (this type comes from grpc-java and represents a gRPC status code)."),(0,r.kt)("li",{parentName:"ul"},"can succeed with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"Feature"),"."),(0,r.kt)("li",{parentName:"ul"},"requires an environment of type ",(0,r.kt)("inlineCode",{parentName:"li"},"ZEnv")," to run.")),(0,r.kt)("p",null,"In this case, our effect is built on top of a pure function ",(0,r.kt)("inlineCode",{parentName:"p"},"findFeature")," that returns ",(0,r.kt)("inlineCode",{parentName:"p"},"Some(feature)"),"\nif there is a feature in the database that corresponds to the given point, or ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," otherwise."),(0,r.kt)("p",null,"We use ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO.fromOption")," to turn the ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Feature]")," into an effect of type ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[Option[Nothing], Feature]"),"\nwhich means that it can either succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," or fail with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Nothing]")," (the only possible value of this type is ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," since there are no instances of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Nothing"),"). We\nthen use ",(0,r.kt)("inlineCode",{parentName:"p"},"mapError")," to map the case of an error to gRPC's ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND")," status."),(0,r.kt)("h3",{id:"server-side-streaming-rpc"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next let's look at one of our streaming RPCs. ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures")," is a server-side\nstreaming RPC, so we need to send back multiple ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s to our client."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def listFeatures(request: Rectangle): ZStream[ZEnv, Status, Feature] = {\n val left = request.getLo.longitude min request.getHi.longitude\n val right = request.getLo.longitude max request.getHi.longitude\n val top = request.getLo.latitude max request.getHi.latitude\n val bottom = request.getLo.latitude min request.getHi.latitude\n\n ZStream.fromIterable(\n features.filter { feature =>\n val lat = feature.getLocation.latitude\n val lon = feature.getLocation.longitude\n lon >= left && lon <= right && lat >= bottom && lat <= top\n }\n )\n}\n")),(0,r.kt)("p",null,"Like the simple RPC, this method gets a request object (the ",(0,r.kt)("inlineCode",{parentName:"p"},"Rectangle")," in which\nour client wants to find ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s) and returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream[ZEnv, Status, Feature]"),", which represents an effectful stream that can produce, provided an environment of type\n",(0,r.kt)("inlineCode",{parentName:"p"},"ZEnv")," zero or more elements of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," and fail with a value of type of ",(0,r.kt)("inlineCode",{parentName:"p"},"Status"),"."),(0,r.kt)("p",null," This time, the stream does not need the environment and can not ever fail (since\nour database is a constant in the same process!)"),(0,r.kt)("p",null," We build the stream from a Scala collection we build by filtering through the features\nsequence. ZIO gRPC takes over streaming the response to the client when the stream\ngets executed."),(0,r.kt)("h3",{id:"client-side-streaming-rpc"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now let's look at something a little more complicated: the client-side streaming\nmethod ",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute()"),", where we get a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s from the client and\nreturn a single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," with information about their trip once the stream finishes."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def recordRoute(\n request: zio.stream.Stream[Status, Point]\n): ZIO[Clock, Status, RouteSummary] = {\n // Zips each element with the previous element, initially accompanied by None.\n request.zipWithPrevious\n .fold(RouteSummary()) {\n case (summary, (maybePrevPoint, currentPoint)) =>\n // Compute the next status based on the current status.\n summary.copy(\n pointCount = summary.pointCount + 1,\n featureCount =\n summary.featureCount + (if (findFeature(currentPoint).isDefined) 1\n else 0),\n distance = summary.distance + maybePrevPoint\n .map(calcDistance(_, currentPoint))\n .getOrElse(0)\n )\n }\n .timed // returns a new effect that times the execution\n .map {\n case (duration, summary) =>\n summary.copy(elapsedTime = (duration.toMillis / 1000).toInt)\n }\n}\n")),(0,r.kt)("p",null,"Here, our method gets a stream that is produced by the client. As you can see\nfrom the signature of this method, our goal would be to turn this stream into an\neffect that results in a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," contains the number of points, number of features on the trip, total distance passed, and the time it took. As this summary can be built iteratively we use fold, which takes the summary and new input to compute the next summary. Since we are\nadding up the distance between successive pair of points, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithPrevious"),"\nthat gives us a pair ",(0,r.kt)("inlineCode",{parentName:"p"},"(Option[Point], Point)")," where the left element represents the previous element in the stream (which is initially None)."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fold")," method gives us a ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[Status, RouteSummary]"),". Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"timed")," method we are getting a new ZIO effect that upon success gives us the a tuple ",(0,r.kt)("inlineCode",{parentName:"p"},"(zio.duration.Duration, RouteSummary)")," where the duration represents the time it took to process\nthe effect thus far. We then use ",(0,r.kt)("inlineCode",{parentName:"p"},"map")," to turn it back to a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," that contains the elapsed time in seconds."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def routeChat(\n request: zio.stream.Stream[Status, RouteNote]\n): ZStream[ZEnv, Status, RouteNote] =\n request.flatMap { note =>\n // By using flatMap, we can map each RouteNote we receive to a stream with\n // the existing RouteNotes for that location, and those sub-streams are going\n // to get concatenated.\n // We start from an effect that updates the map with the new RouteNote,\n // and returns the notes associated with the location just before the update.\n val updateMapEffect: UIO[List[RouteNote]] =\n routeNotesRef.modify { routeNotes =>\n val messages = routeNotes.getOrElse(note.getLocation, Nil)\n (messages, routeNotes.updated(note.getLocation, note :: messages))\n }\n // We create a stream from the effect.\n ZStream.fromIterableM(updateMapEffect)\n }\n")),(0,r.kt)("p",null,"As with our client-side streaming example, we are getting a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s, except this time we are also returning a stream of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s. Although each side will always get the other's messages in the\norder they were written, both the client and server can read and write in any\norder \u2014 the streams operate completely independently."),(0,r.kt)("p",null,"In this example, we are using ",(0,r.kt)("inlineCode",{parentName:"p"},"flatMap")," on the incoming stream to map each input to a new\neffectful stream representing the notes that are available in that location. We are using ",(0,r.kt)("inlineCode",{parentName:"p"},"Ref#modify")," to mutate the collection of notes in the given location and return the list of notes available just prior to the update."),(0,r.kt)("h2",{id:"starting-the-server"},"Starting the server"),(0,r.kt)("p",null,"Once we've implemented all our methods, we also need to start up a gRPC server\nso that clients can actually use our service. The following snippet shows how we\ndo this for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide")," service:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'object RouteGuideServer extends ServerMain {\n override def port: Int = 8980\n\n val featuresDatabase = JsonFormat.fromJsonString[FeatureDatabase](\n Source.fromResource("route_guide_db.json").mkString\n )\n\n val createRouteGuide = for {\n routeNotes <- Ref.make(Map.empty[Point, List[RouteNote]])\n } yield new RouteGuideService(featuresDatabase.feature, routeNotes)\n\n def services: ServiceList[zio.ZEnv] =\n ServiceList.addM(createRouteGuide)\n}\n')),(0,r.kt)("p",null,"ZIO gRPC provides a base trait to quickly set up gRPC services with zero boilerplate."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"We override the port we are going to use (default is 9000)"),(0,r.kt)("li",{parentName:"ol"},"Create an effect that constructs an instance of our service (we need an effectful construction since\nour service constructor takes a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.Ref"),")"),(0,r.kt)("li",{parentName:"ol"},"Override ",(0,r.kt)("inlineCode",{parentName:"li"},"def services")," to return a ",(0,r.kt)("inlineCode",{parentName:"li"},"ServiceList")," that contains our service.")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," is meant to be used for simple applications. If you need to do more in your initialization, you can take a look at the source code of ",(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," and customize."),(0,r.kt)("h2",{id:"creating-the-client"},"Creating the client"),(0,r.kt)("p",null,"In this section, we'll look at creating a client for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide"),"\nservice. You can see our complete example client code in\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/scalapb/zio-grpc/blob/master/examples/src/main/scala/zio_grpc/examples/routeguide/RouteGuideClientApp.scala"},"RouteGuideClientApp.scala"),"."),(0,r.kt)("h3",{id:"instantiating-a-client"},"Instantiating a client"),(0,r.kt)("p",null,"To call service methods, we first need to create a client. There are two patterns\nto work with clients:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.managed")," to instantiate a client inside a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.ZManaged"),". Then through calling its ",(0,r.kt)("inlineCode",{parentName:"li"},"use")," method, the client can be accessed and method can be called on it."),(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.live")," to create a ",(0,r.kt)("inlineCode",{parentName:"li"},"ZLayer")," that can be used to provide a client as a singleton to our program through the environment. In that case, throughout the program we use accessor methods, defined statically in ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient")," that expect the client to be available in the environment.")),(0,r.kt)("p",null,"Throughout this tutorial, we will follow the second pattern. We create a ",(0,r.kt)("inlineCode",{parentName:"p"},"Layer")," that can provide a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val clientLayer: Layer[Throwable, RouteGuideClient] =\n RouteGuideClient.live(\n ZManagedChannel(\n ManagedChannelBuilder.forAddress("localhost", 8980).usePlaintext()\n )\n )\n')),(0,r.kt)("h3",{id:"calling-service-methods"},"Calling service methods"),(0,r.kt)("p",null,"Now let's look at how we call our service methods."),(0,r.kt)("p",null,"As described above, ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," contains accessor methods for each RPC\nthat return an effect or a stream that needs a client in the environment to be ran:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def getFeature(req: Point):\n ZIO[RouteGuideClient, Status, Feature]\n\ndef listFeatures(req: Rectangle):\n ZStream[RouteGuideClient, Status, Feature]\n\ndef recordRoute[R0](req: ZStream[R0, Status, Point]):\n ZIO[RouteGuideClient with R0, Status, RouteSummary]\n\ndef routeChat[R0](req: ZStream[R0, Status, RouteNote]):\n ZStream[RouteGuideClient with R0, Status, RouteNote]\n")),(0,r.kt)("h3",{id:"simple-rpc-1"},"Simple RPC"),(0,r.kt)("p",null,"Calling the simple RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"GetFeature")," on the static accessor stub is as\nstraightforward as instantiating a local effect:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def getFeature(\n lat: Int,\n lng: Int\n): ZIO[RouteGuideClient with Console, Status, Unit] =\n (for {\n f <- RouteGuideClient.getFeature(Point(lat, lng))\n _ <- putStrLn(s"""Found feature called "${f.name}".""")\n } yield ()).catchSome {\n case status if status == Status.NOT_FOUND =>\n putStrLn(s"Feature not found: ${status.toString()}")\n }\n')),(0,r.kt)("p",null,"We create and populate a request protocol buffer object (in our case\n",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), pass it to the ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method on our accessor, and get\nback an effect that needs a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," environment. We chain\nthe response with a call to ",(0,r.kt)("inlineCode",{parentName:"p"},"putStrLn")," to print the result on the console,\nand we catch the ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND"),' response and print an error. All other errors\nare not handled at this level and will "bubble up" up to the program\'s ',(0,r.kt)("inlineCode",{parentName:"p"},"exitCode")," handler."),(0,r.kt)("h3",{id:"server-side-streaming-rpc-1"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next, let's look at a server-side streaming call to ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures"),", which\nreturns a stream of geographical ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'_ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach {\n case (feature, index) =>\n putStrLn(s"Result #${index + 1}: $feature")\n }\n')),(0,r.kt)("p",null,"Now ",(0,r.kt)("inlineCode",{parentName:"p"},"listFeatures")," returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream"),". We use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithIndex")," to get a stream\nwhere each of the original elements are accompanied with a zero-based index. We turn\nthis stream into a single effect that processes the entire stream by calling ",(0,r.kt)("inlineCode",{parentName:"p"},"foreach"),"\nand providing it with a function that maps each element into an effect. In this case,\nthe effect prints the feature."),(0,r.kt)("h3",{id:"client-side-streaming-rpc-1"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now for something a little more complicated: the client-side streaming method\n",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute"),", where we send a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s to the server and get back\na single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def recordRoute(numPoints: Int) =\n for {\n summary <- RouteGuideClient.recordRoute(\n ZStream\n .repeatEffect(\n nextIntBetween(0, features.size).map(features(_).getLocation)\n )\n .tap(p => putStrLn(s"Visiting (${p.latitude}, ${p.longitude})"))\n .schedule(Schedule.spaced(300.millis))\n .take(numPoints)\n )\n _ <- putStrLn(\n s"Finished trip with ${summary.pointCount} points. " +\n s"Passed ${summary.featureCount} features. " +\n s"Travelled ${summary.distance} meters. " +\n s"It took ${summary.elapsedTime} seconds."\n )\n } yield ()\n')),(0,r.kt)("p",null,"Here, we pass into ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute")," an effectful stream that randomly picks an element from the ",(0,r.kt)("inlineCode",{parentName:"p"},"features")," collection (a constant), and insert random delay between elements."),(0,r.kt)("p",null,"Like all the other accessor methods it's worth noting that no side effect happens upon calling ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute"),". The method returns immediately giving us an effect that represents sending this stream to the server. When the effect ultimately run it can succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," once the entire stream has been sent to the server."),(0,r.kt)("p",null,"In this example, we chain to this effect an effect to print the summary to the console."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc-1"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val routeChat =\n for {\n res <-\n RouteGuideClient\n .routeChat(\n ZStream(\n RouteNote(\n location = Some(Point(0, 0)),\n message = "First message"\n ),\n RouteNote(\n location = Some(Point(0, 10_000_000)),\n message = "Second Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 0)),\n message = "Third Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 10_000_000)),\n message = "Four Message"\n )\n ).tap { note =>\n putStrLn(\n s"""Sending message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n )\n }\n )\n .foreach { note =>\n putStrLn(\n s"""Got message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n )\n }\n } yield ()\n')),(0,r.kt)("p",null,"In this method, we both get and return a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\nRouteNotes. Here both streams execute independently at the same time. Although each side will always\nget the other's messages in the order they were written, both the client and\nserver can read and write in any order \u2014 the streams operate completely\nindependently."),(0,r.kt)("h3",{id:"providing-the-client-layer-into-the-application-logic"},"Providing the client layer into the application logic"),(0,r.kt)("p",null,"All the effects we created were dependent on a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," available in the environment. We earlier instantiated a ",(0,r.kt)("inlineCode",{parentName:"p"},"clientLayer"),", so we can provide it to our application logic at the top-level (the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val myAppLogic =\n for {\n // Looking for a valid feature\n _ <- getFeature(409146138, -746188906)\n // Looking for a missing feature\n _ <- getFeature(0, 0)\n\n // Calls listFeatures with a rectangle of interest. Prints\n // each response feature as it arrives.\n // start: listFeatures\n _ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach {\n case (feature, index) =>\n putStrLn(s"Result #${index + 1}: $feature")\n }\n // end: listFeatures\n\n _ <- recordRoute(10)\n\n _ <- routeChat\n } yield ()\n\nfinal def run(args: List[String]) =\n myAppLogic.provideCustomLayer(clientLayer).exitCode\n')),(0,r.kt)("h2",{id:"try-it-out"},"Try it out!"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Run the server:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideServer"\n'))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"From another terminal, run the client:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideClientApp"\n')))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},'This document, "ZIO gRPC: Basics Tutorial", is a derivative of ',(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/docs/languages/java/basics/"},'"gRPC ',"\u2013",' Basics Tutorial"')," by ",(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/"},"gRPC Authors"),", used under ",(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0"),'. "ZIO gRPC: Basics Tutorial" is licensed under ',(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0")," by Nadav Samet.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2ed64f4e.3dc9e2e0.js b/assets/js/2ed64f4e.3dc9e2e0.js deleted file mode 100644 index a4b35ccbb..000000000 --- a/assets/js/2ed64f4e.3dc9e2e0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[596],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return d}});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(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 s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},l={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),m=p(n),d=o,f=m["".concat(s,".").concat(d)]||m[d]||l[d]||a;return n?r.createElement(f,c(c({ref:t},u),{},{components:n})):r.createElement(f,c({ref:t},u))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var p=2;p ZIO[Any, StatusException, A]): RequestContext => ZIO[Any, StatusException, A] = {\n rc => io(rc).zipLeft(accessLog(rc)).tapErrorCause(logCause(rc, _))\n }\n\n override def stream[A](\n io: Any => ZStream[Any, StatusException, A]): RequestContext => ZStream[Any, StatusException, A] = {\n rc => (io(rc) ++ ZStream.fromZIO(accessLog(rc)).drain).onError(logCause(rc, _))\n }\n}\n")),(0,a.kt)("p",null,"and then we apply it to our service:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-scala"},'import myexample.testservice.ZioTestservice._\nimport myexample.testservice.{Request, Response}\n\nobject MyService extends SimpleService {\n def sayHello(req: Request): ZIO[Any, StatusException, Response] =\n ZIO.succeed(Response(s"Hello user"))\n}\n\n// Note we now have a service with a RequestContext as context.\nval decoratedService: ZSimpleService[RequestContext] =\n MyService.transform(new LoggingTransform)\n// decoratedService: ZSimpleService[RequestContext] = myexample.testservice.ZioTestservice$GSimpleService$$anon$5@6c42e041\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2ed64f4e.b357c219.js b/assets/js/2ed64f4e.b357c219.js new file mode 100644 index 000000000..14b74006f --- /dev/null +++ b/assets/js/2ed64f4e.b357c219.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[596],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(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 s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},l={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),m=p(n),f=o,d=m["".concat(s,".").concat(f)]||m[f]||l[f]||a;return n?r.createElement(d,c(c({ref:t},u),{},{components:n})):r.createElement(d,c({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var p=2;p ZIO[Any, StatusException, A]): RequestContext => ZIO[Any, StatusException, A] = {\n rc => io(rc).zipLeft(accessLog(rc)).tapErrorCause(logCause(rc, _))\n }\n\n override def stream[A](\n io: Any => ZStream[Any, StatusException, A]): RequestContext => ZStream[Any, StatusException, A] = {\n rc => (io(rc) ++ ZStream.fromZIO(accessLog(rc)).drain).onError(logCause(rc, _))\n }\n}\n")),(0,a.kt)("p",null,"and then we apply it to our service:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-scala"},'import myexample.testservice.ZioTestservice._\nimport myexample.testservice.{Request, Response}\n\nobject MyService extends SimpleService {\n def sayHello(req: Request): ZIO[Any, StatusException, Response] =\n ZIO.succeed(Response(s"Hello user"))\n}\n\n// Note we now have a service with a RequestContext as context.\nval decoratedService: ZSimpleService[RequestContext] =\n MyService.transform(new LoggingTransform)\n// decoratedService: ZSimpleService[RequestContext] = myexample.testservice.ZioTestservice$GSimpleService$$anon$5@1b53f6f3\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3a2a6d86.51f62376.js b/assets/js/3a2a6d86.51f62376.js new file mode 100644 index 000000000..26b1aa921 --- /dev/null +++ b/assets/js/3a2a6d86.51f62376.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[292],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,v=u["".concat(c,".").concat(m)]||u[m]||d[m]||i;return n?r.createElement(v,o(o({ref:t},l),{},{components:n})):r.createElement(v,o({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var p=2;p IO[Status, User]")," to find the user."),(0,i.kt)("p",null,"For example, we can provide a function that returns an effect that always succeeds:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'val fixedUserService =\n MyService.transformContextZIO((rc: RequestContext) => ZIO.succeed(User("foo")))\n// fixedUserService: myexample.testservice.ZioTestservice.GSimpleService[RequestContext, StatusException] = myexample.testservice.ZioTestservice$GSimpleService$$anon$5@77291fc1\n')),(0,i.kt)("p",null,"and we got our service with context of type ",(0,i.kt)("inlineCode",{parentName:"p"},"RequestContext")," so it can be bound to a gRPC server."),(0,i.kt)("h3",{id:"accessing-metadata"},"Accessing metadata"),(0,i.kt)("p",null,"Here is how we would extract a user from a metadata header:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'import zio.IO\nimport scalapb.zio_grpc.{ServiceList, ServerMain}\n\nval UserKey = io.grpc.Metadata.Key.of(\n "user-key", io.grpc.Metadata.ASCII_STRING_MARSHALLER)\n// UserKey: io.grpc.Metadata.Key[String] = Key{name=\'user-key\'}\n\ndef findUser(rc: RequestContext): IO[StatusException, User] =\n rc.metadata.get(UserKey).flatMap {\n case Some(name) => ZIO.succeed(User(name))\n case _ => ZIO.fail(\n Status.UNAUTHENTICATED.withDescription("No access!").asException)\n }\n\nval rcService =\n MyService.transformContextZIO(findUser)\n// rcService: myexample.testservice.ZioTestservice.GSimpleService[RequestContext, StatusException] = myexample.testservice.ZioTestservice$GSimpleService$$anon$5@7e1ad83c\n\nobject MyServer extends ServerMain {\n def services = ServiceList.add(rcService)\n}\n')),(0,i.kt)("h3",{id:"context-transformations-that-depends-on-a-service"},"Context transformations that depends on a service"),(0,i.kt)("p",null,"A context transformation may introduce a dependency on another service. For example, you\nmay want to organize your code such that there is a ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase")," service that provides\na ",(0,i.kt)("inlineCode",{parentName:"p"},"fetchUser")," effect that retrieves users from a database. Here is how you can do this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"trait UserDatabase {\n def fetchUser(name: String): IO[StatusException, User]\n}\n\nobject UserDatabase {\n val layer = zio.ZLayer.succeed(\n new UserDatabase {\n def fetchUser(name: String): IO[StatusException, User] =\n ZIO.succeed(User(name))\n })\n}\n")),(0,i.kt)("p",null,"Now, The context transformation effect we apply may introduce an additional environmental dependency to our service. For example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'import zio.Clock._\nimport zio.Duration._\n\nval myServiceAuthWithDatabase: ZIO[UserDatabase, Nothing, ZSimpleService[RequestContext]] =\n ZIO.serviceWith[UserDatabase](\n userDatabase =>\n MyService.transformContextZIO {\n (rc: RequestContext) =>\n rc.metadata.get(UserKey)\n .someOrFail(Status.UNAUTHENTICATED.asException)\n .flatMap(userDatabase.fetchUser(_))\n }\n )\n// myServiceAuthWithDatabase: ZIO[UserDatabase, Nothing, ZSimpleService[RequestContext]] = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myServiceAuthWithDatabase(context.md:104)",\n// first = Sync(\n// trace = "repl.MdocSession.MdocApp.myServiceAuthWithDatabase(context.md:104)",\n// eval = zio.ZIO$ServiceWithZIOPartiallyApplied$$$Lambda$11934/1676433133@68f20039\n// ),\n// successK = zio.ZIO$$$Lambda$11925/1009964979@a4c55a1\n// )\n')),(0,i.kt)("p",null,"Now our service can be built from an effect that depends on ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase"),". This effect can be\nadded to a ",(0,i.kt)("inlineCode",{parentName:"p"},"ServiceList")," using ",(0,i.kt)("inlineCode",{parentName:"p"},"addZIO"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"object MyServer2 extends ServerMain {\n def services = ServiceList\n .addZIO(myServiceAuthWithDatabase)\n .provide(UserDatabase.layer)\n}\n")),(0,i.kt)("h2",{id:"using-a-service-as-zlayer"},"Using a service as ZLayer"),(0,i.kt)("p",null,"If you require more flexibility than provided through ",(0,i.kt)("inlineCode",{parentName:"p"},"ServerMain"),", you can construct\nthe server directly."),(0,i.kt)("p",null,"We first turn our service into a ZLayer:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"val myServiceLayer = zio.ZLayer(myServiceAuthWithDatabase)\n// myServiceLayer: zio.ZLayer[UserDatabase, Nothing, ZSimpleService[RequestContext]] = Suspend(\n// self = zio.ZLayer$$$Lambda$11936/1494494936@1171e736\n// )\n")),(0,i.kt)("p",null,"Notice how the dependencies moved to the input side of the ",(0,i.kt)("inlineCode",{parentName:"p"},"ZLayer")," and the resulting layer is of\ntype ",(0,i.kt)("inlineCode",{parentName:"p"},"ZSimpleService[RequestContext]"),"."),(0,i.kt)("p",null,"To use this layer in an app, we can wire it like so:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"import scalapb.zio_grpc.ServerLayer\nimport scalapb.zio_grpc.Server\nimport zio.ZLayer\n\nval serviceList = ServiceList\n .addFromEnvironment[ZSimpleService[RequestContext]]\n// serviceList: ServiceList[Any with ZSimpleService[RequestContext]] = scalapb.zio_grpc.ServiceList@51165b2b\n\nval serverLayer =\n ServerLayer.fromServiceList(\n io.grpc.ServerBuilder.forPort(9000),\n serviceList\n )\n// serverLayer: ZLayer[Any with ZSimpleService[RequestContext], Throwable, Server] = Suspend(\n// self = zio.ZLayer$ScopedEnvironmentPartiallyApplied$$$Lambda$11947/302417759@299d7af8\n// )\n\nval ourApp =\n ZLayer.make[Server](\n serverLayer,\n myServiceLayer,\n UserDatabase.layer\n )\n// ourApp: ZLayer[Any, Throwable, Server] = Suspend(\n// self = zio.ZLayer$ZLayerProvideSomeOps$$$Lambda$11949/1055017691@4114d337\n// )\n\nobject LayeredApp extends zio.ZIOAppDefault {\n def run = ourApp.launch.exitCode\n}\n")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"serverLayer")," creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"Server")," from a ",(0,i.kt)("inlineCode",{parentName:"p"},"ZSimpleService")," layer and still depends on a ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase"),". Then, ",(0,i.kt)("inlineCode",{parentName:"p"},"ourApp")," feeds a ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase.layer")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"serverLayer")," to produce\na ",(0,i.kt)("inlineCode",{parentName:"p"},"Server")," that doesn't depend on anything. In the ",(0,i.kt)("inlineCode",{parentName:"p"},"run")," method we launch the server layer."),(0,i.kt)("h2",{id:"implementing-a-service-with-dependencies"},"Implementing a service with dependencies"),(0,i.kt)("p",null,"In this scenario, your service depends on two additional services, ",(0,i.kt)("inlineCode",{parentName:"p"},"DepA")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"DepB"),". Following ",(0,i.kt)("a",{parentName:"p",href:"https://zio.dev/reference/service-pattern/"},"ZIO's service pattern"),", we accept the (interaces of the ) dependencies as constructor parameters."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'trait DepA {\n def methodA(param: String): ZIO[Any, Nothing, Int]\n}\n\nobject DepA {\n val layer = ZLayer.succeed[DepA](new DepA {\n def methodA(param: String) = ???\n })\n}\n\nobject DepB {\n val layer = ZLayer.succeed[DepB](new DepB {\n def methodB(param: Float) = ???\n })\n}\n\ntrait DepB {\n def methodB(param: Float): ZIO[Any, Nothing, Double]\n}\n\ncase class MyService2(depA: DepA, depB: DepB) extends ZSimpleService[User] {\n def sayHello(req: Request, user: User): ZIO[Any, StatusException, Response] =\n for {\n num1 <- depA.methodA(user.name)\n num2 <- depB.methodB(12.3f)\n _ <- printLine("I am here $num1 $num2!").orDie\n } yield Response(s"Hello, ${user.name}")\n}\n\nobject MyService2 {\n val layer: ZLayer[DepA with DepB, Nothing, ZSimpleService[RequestContext]] =\n ZLayer.fromFunction {\n (depA: DepA, depB: DepB) =>\n MyService2(depA, depB).transformContextZIO(findUser(_))\n }\n}\n')),(0,i.kt)("p",null,"Our service layer now depends on the ",(0,i.kt)("inlineCode",{parentName:"p"},"DepA")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"DepB")," interfaces. A server can be created like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"object MyServer3 extends zio.ZIOAppDefault {\n\n val serverLayer =\n ServerLayer.fromServiceList(\n io.grpc.ServerBuilder.forPort(9000),\n ServiceList.addFromEnvironment[ZSimpleService[RequestContext]]\n )\n\n val appLayer = ZLayer.make[Server](\n serverLayer,\n DepA.layer,\n DepB.layer,\n MyService2.layer\n )\n\n def run = ourApp.launch.exitCode\n}\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3a2a6d86.7d5c9a66.js b/assets/js/3a2a6d86.7d5c9a66.js deleted file mode 100644 index a6db4a856..000000000 --- a/assets/js/3a2a6d86.7d5c9a66.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[292],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,v=u["".concat(c,".").concat(m)]||u[m]||d[m]||i;return n?r.createElement(v,o(o({ref:t},l),{},{components:n})):r.createElement(v,o({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var p=2;p IO[Status, User]")," to find the user."),(0,i.kt)("p",null,"For example, we can provide a function that returns an effect that always succeeds:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'val fixedUserService =\n MyService.transformContextZIO((rc: RequestContext) => ZIO.succeed(User("foo")))\n// fixedUserService: myexample.testservice.ZioTestservice.GSimpleService[RequestContext, StatusException] = myexample.testservice.ZioTestservice$GSimpleService$$anon$5@a82beae\n')),(0,i.kt)("p",null,"and we got our service with context of type ",(0,i.kt)("inlineCode",{parentName:"p"},"RequestContext")," so it can be bound to a gRPC server."),(0,i.kt)("h3",{id:"accessing-metadata"},"Accessing metadata"),(0,i.kt)("p",null,"Here is how we would extract a user from a metadata header:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'import zio.IO\nimport scalapb.zio_grpc.{ServiceList, ServerMain}\n\nval UserKey = io.grpc.Metadata.Key.of(\n "user-key", io.grpc.Metadata.ASCII_STRING_MARSHALLER)\n// UserKey: io.grpc.Metadata.Key[String] = Key{name=\'user-key\'}\n\ndef findUser(rc: RequestContext): IO[StatusException, User] =\n rc.metadata.get(UserKey).flatMap {\n case Some(name) => ZIO.succeed(User(name))\n case _ => ZIO.fail(\n Status.UNAUTHENTICATED.withDescription("No access!").asException)\n }\n\nval rcService =\n MyService.transformContextZIO(findUser)\n// rcService: myexample.testservice.ZioTestservice.GSimpleService[RequestContext, StatusException] = myexample.testservice.ZioTestservice$GSimpleService$$anon$5@36bbbde2\n\nobject MyServer extends ServerMain {\n def services = ServiceList.add(rcService)\n}\n')),(0,i.kt)("h3",{id:"context-transformations-that-depends-on-a-service"},"Context transformations that depends on a service"),(0,i.kt)("p",null,"A context transformation may introduce a dependency on another service. For example, you\nmay want to organize your code such that there is a ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase")," service that provides\na ",(0,i.kt)("inlineCode",{parentName:"p"},"fetchUser")," effect that retrieves users from a database. Here is how you can do this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"trait UserDatabase {\n def fetchUser(name: String): IO[StatusException, User]\n}\n\nobject UserDatabase {\n val layer = zio.ZLayer.succeed(\n new UserDatabase {\n def fetchUser(name: String): IO[StatusException, User] =\n ZIO.succeed(User(name))\n })\n}\n")),(0,i.kt)("p",null,"Now, The context transformation effect we apply may introduce an additional environmental dependency to our service. For example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'import zio.Clock._\nimport zio.Duration._\n\nval myServiceAuthWithDatabase: ZIO[UserDatabase, Nothing, ZSimpleService[RequestContext]] =\n ZIO.serviceWith[UserDatabase](\n userDatabase =>\n MyService.transformContextZIO {\n (rc: RequestContext) =>\n rc.metadata.get(UserKey)\n .someOrFail(Status.UNAUTHENTICATED.asException)\n .flatMap(userDatabase.fetchUser(_))\n }\n )\n// myServiceAuthWithDatabase: ZIO[UserDatabase, Nothing, ZSimpleService[RequestContext]] = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myServiceAuthWithDatabase(context.md:104)",\n// first = Sync(\n// trace = "repl.MdocSession.MdocApp.myServiceAuthWithDatabase(context.md:104)",\n// eval = zio.ZIO$ServiceWithZIOPartiallyApplied$$$Lambda$11914/467520303@26f3aaa5\n// ),\n// successK = zio.ZIO$$$Lambda$11905/1122445729@13ee00f\n// )\n')),(0,i.kt)("p",null,"Now our service can be built from an effect that depends on ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase"),". This effect can be\nadded to a ",(0,i.kt)("inlineCode",{parentName:"p"},"ServiceList")," using ",(0,i.kt)("inlineCode",{parentName:"p"},"addZIO"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"object MyServer2 extends ServerMain {\n def services = ServiceList\n .addZIO(myServiceAuthWithDatabase)\n .provide(UserDatabase.layer)\n}\n")),(0,i.kt)("h2",{id:"using-a-service-as-zlayer"},"Using a service as ZLayer"),(0,i.kt)("p",null,"If you require more flexibility than provided through ",(0,i.kt)("inlineCode",{parentName:"p"},"ServerMain"),", you can construct\nthe server directly."),(0,i.kt)("p",null,"We first turn our service into a ZLayer:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"val myServiceLayer = zio.ZLayer(myServiceAuthWithDatabase)\n// myServiceLayer: zio.ZLayer[UserDatabase, Nothing, ZSimpleService[RequestContext]] = Suspend(\n// self = zio.ZLayer$$$Lambda$11916/1636601297@1398a515\n// )\n")),(0,i.kt)("p",null,"Notice how the dependencies moved to the input side of the ",(0,i.kt)("inlineCode",{parentName:"p"},"ZLayer")," and the resulting layer is of\ntype ",(0,i.kt)("inlineCode",{parentName:"p"},"ZSimpleService[RequestContext]"),"."),(0,i.kt)("p",null,"To use this layer in an app, we can wire it like so:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"import scalapb.zio_grpc.ServerLayer\nimport scalapb.zio_grpc.Server\nimport zio.ZLayer\n\nval serviceList = ServiceList\n .addFromEnvironment[ZSimpleService[RequestContext]]\n// serviceList: ServiceList[Any with ZSimpleService[RequestContext]] = scalapb.zio_grpc.ServiceList@4ec330c0\n\nval serverLayer =\n ServerLayer.fromServiceList(\n io.grpc.ServerBuilder.forPort(9000),\n serviceList\n )\n// serverLayer: ZLayer[Any with ZSimpleService[RequestContext], Throwable, Server] = Suspend(\n// self = zio.ZLayer$ScopedEnvironmentPartiallyApplied$$$Lambda$11927/1070393493@755e1d3f\n// )\n\nval ourApp =\n ZLayer.make[Server](\n serverLayer,\n myServiceLayer,\n UserDatabase.layer\n )\n// ourApp: ZLayer[Any, Throwable, Server] = Suspend(\n// self = zio.ZLayer$ZLayerProvideSomeOps$$$Lambda$11929/1630756541@316b503\n// )\n\nobject LayeredApp extends zio.ZIOAppDefault {\n def run = ourApp.launch.exitCode\n}\n")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"serverLayer")," creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"Server")," from a ",(0,i.kt)("inlineCode",{parentName:"p"},"ZSimpleService")," layer and still depends on a ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase"),". Then, ",(0,i.kt)("inlineCode",{parentName:"p"},"ourApp")," feeds a ",(0,i.kt)("inlineCode",{parentName:"p"},"UserDatabase.layer")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"serverLayer")," to produce\na ",(0,i.kt)("inlineCode",{parentName:"p"},"Server")," that doesn't depend on anything. In the ",(0,i.kt)("inlineCode",{parentName:"p"},"run")," method we launch the server layer."),(0,i.kt)("h2",{id:"implementing-a-service-with-dependencies"},"Implementing a service with dependencies"),(0,i.kt)("p",null,"In this scenario, your service depends on two additional services, ",(0,i.kt)("inlineCode",{parentName:"p"},"DepA")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"DepB"),". Following ",(0,i.kt)("a",{parentName:"p",href:"https://zio.dev/reference/service-pattern/"},"ZIO's service pattern"),", we accept the (interaces of the ) dependencies as constructor parameters."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'trait DepA {\n def methodA(param: String): ZIO[Any, Nothing, Int]\n}\n\nobject DepA {\n val layer = ZLayer.succeed[DepA](new DepA {\n def methodA(param: String) = ???\n })\n}\n\nobject DepB {\n val layer = ZLayer.succeed[DepB](new DepB {\n def methodB(param: Float) = ???\n })\n}\n\ntrait DepB {\n def methodB(param: Float): ZIO[Any, Nothing, Double]\n}\n\ncase class MyService2(depA: DepA, depB: DepB) extends ZSimpleService[User] {\n def sayHello(req: Request, user: User): ZIO[Any, StatusException, Response] =\n for {\n num1 <- depA.methodA(user.name)\n num2 <- depB.methodB(12.3f)\n _ <- printLine("I am here $num1 $num2!").orDie\n } yield Response(s"Hello, ${user.name}")\n}\n\nobject MyService2 {\n val layer: ZLayer[DepA with DepB, Nothing, ZSimpleService[RequestContext]] =\n ZLayer.fromFunction {\n (depA: DepA, depB: DepB) =>\n MyService2(depA, depB).transformContextZIO(findUser(_))\n }\n}\n')),(0,i.kt)("p",null,"Our service layer now depends on the ",(0,i.kt)("inlineCode",{parentName:"p"},"DepA")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"DepB")," interfaces. A server can be created like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},"object MyServer3 extends zio.ZIOAppDefault {\n\n val serverLayer =\n ServerLayer.fromServiceList(\n io.grpc.ServerBuilder.forPort(9000),\n ServiceList.addFromEnvironment[ZSimpleService[RequestContext]]\n )\n\n val appLayer = ZLayer.make[Server](\n serverLayer,\n DepA.layer,\n DepB.layer,\n MyService2.layer\n )\n\n def run = ourApp.launch.exitCode\n}\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/47bf511f.5545cdc7.js b/assets/js/47bf511f.5545cdc7.js new file mode 100644 index 000000000..f20b4cd87 --- /dev/null +++ b/assets/js/47bf511f.5545cdc7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[215],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,h=d["".concat(p,".").concat(m)]||d[m]||u[m]||l;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=d;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var s=2;s=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,h=d["".concat(p,".").concat(m)]||d[m]||u[m]||l;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=d;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var s=2;s=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=n.createContext({}),p=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},u=function(e){var r=p(e.components);return n.createElement(c.Provider,{value:r},e.children)},l={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=p(t),f=o,m=d["".concat(c,".").concat(f)]||d[f]||l[f]||a;return t?n.createElement(m,s(s({ref:r},u),{},{components:t})):n.createElement(m,s({ref:r},u))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=d;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=n.createContext({}),p=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},u=function(e){var r=p(e.components);return n.createElement(c.Provider,{value:r},e.children)},l={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=p(t),f=o,m=d["".concat(c,".").concat(f)]||d[f]||l[f]||a;return t?n.createElement(m,s(s({ref:r},u),{},{components:t})):n.createElement(m,s({ref:r},u))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=d;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=a.createContext({}),l=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=l(e.components);return a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(t),m=r,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||o;return t?a.createElement(f,i(i({ref:n},p),{},{components:t})):a.createElement(f,i({ref:n},p))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,i=new Array(o);i[0]=u;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:r,i[1]=s;for(var l=2;l IO[Status, User]")," to find the user."),(0,o.kt)("p",null,"For example, we can provide a function that returns an effect that always succeeds:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},'val fixedUserService =\n MyService.transformContextM((rc: RequestContext) => ZIO.succeed(User("foo")))\n// fixedUserService: ZSimpleService[Console, Has[RequestContext]] = myexample.testservice.ZioTestservice$ZSimpleService$$anon$6$$anon$7@5d50c6f9\n')),(0,o.kt)("p",null,"and we got our service, which still depends on an environment of type ",(0,o.kt)("inlineCode",{parentName:"p"},"Console"),", however the context is now ",(0,o.kt)("inlineCode",{parentName:"p"},"Has[RequestContext]")," so it can be bound to a gRPC server."),(0,o.kt)("h3",{id:"accessing-metadata"},"Accessing metadata"),(0,o.kt)("p",null,"Here is how we would extract a user from a metadata header:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},'import zio.IO\nimport scalapb.zio_grpc.{ServiceList, ServerMain}\n\nval UserKey = io.grpc.Metadata.Key.of(\n "user-key", io.grpc.Metadata.ASCII_STRING_MARSHALLER)\n// UserKey: io.grpc.Metadata.Key[String] = Key{name=\'user-key\'}\n\ndef findUser(rc: RequestContext): IO[Status, User] =\n rc.metadata.get(UserKey).flatMap {\n case Some(name) => IO.succeed(User(name))\n case _ => IO.fail(Status.UNAUTHENTICATED.withDescription("No access!"))\n }\n\nval rcService =\n MyService.transformContextM(findUser)\n// rcService: ZSimpleService[Console, Has[RequestContext]] = myexample.testservice.ZioTestservice$ZSimpleService$$anon$6$$anon$7@6e4166f6\n\nobject MyServer extends ServerMain {\n def services = ServiceList.add(rcService)\n}\n')),(0,o.kt)("h3",{id:"depending-on-a-service"},"Depending on a service"),(0,o.kt)("p",null,"A context transformation may introduce a dependency on another service. For example, you\nmay want to organize your code such that there is a ",(0,o.kt)("inlineCode",{parentName:"p"},"UserDatabase")," service that provides\na ",(0,o.kt)("inlineCode",{parentName:"p"},"fetchUser")," effect that retrieves users from a database. Here is how you can do this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"type UserDatabase = Has[UserDatabase.Service]\nobject UserDatabase {\n trait Service {\n def fetchUser(name: String): IO[Status, User]\n }\n\n // accessor\n def fetchUser(name: String): ZIO[UserDatabase, Status, User] =\n ZIO.accessM[UserDatabase](_.get.fetchUser(name))\n\n val live = zio.ZLayer.succeed(\n new Service {\n def fetchUser(name: String): IO[Status, User] =\n IO.succeed(User(name))\n })\n}\n")),(0,o.kt)("p",null,"Now,\nThe context transformation effect we apply may introduce an additional environmental dependency to our service. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"import zio.clock._\nimport zio.duration._\n\nval myServiceAuthWithDatabase =\n MyService.transformContextM {\n (rc: RequestContext) =>\n rc.metadata.get(UserKey)\n .someOrFail(Status.UNAUTHENTICATED)\n .flatMap(UserDatabase.fetchUser)\n }\n// myServiceAuthWithDatabase: ZSimpleService[Console with UserDatabase, Has[RequestContext]] = myexample.testservice.ZioTestservice$ZSimpleService$$anon$6$$anon$7@46db627e\n")),(0,o.kt)("p",null,"And now our service not only depends on a ",(0,o.kt)("inlineCode",{parentName:"p"},"Console"),", but also on a ",(0,o.kt)("inlineCode",{parentName:"p"},"UserDatabase"),"."),(0,o.kt)("h2",{id:"using-a-service-as-zlayer"},"Using a service as ZLayer"),(0,o.kt)("p",null,"We can turn our service into a ZLayer:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"val myServiceLive = myServiceAuthWithDatabase.toLayer\n// myServiceLive: zio.ZLayer[Console with UserDatabase, Nothing, Has[ZSimpleService[Any, Has[RequestContext]]]] = Managed(\n// self = zio.ZManaged$$anon$2@15f00ea8\n// )\n")),(0,o.kt)("p",null,"notice how the dependencies moved to the input side of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Layer")," and the resulting layer is of\ntype ",(0,o.kt)("inlineCode",{parentName:"p"},"ZSimpleService[Any, Has[RequestContext]]]"),", which means no environment is expected, and it assumes\na ",(0,o.kt)("inlineCode",{parentName:"p"},"Has[RequestContext]")," context. To use this layer in an app, we can wire it like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"import scalapb.zio_grpc.ServerLayer\n\nval serverLayer =\n ServerLayer.fromServiceLayer(\n io.grpc.ServerBuilder.forPort(9000)\n )(myServiceLive)\n// serverLayer: zio.ZLayer[Console with UserDatabase, Throwable, Has[scalapb.zio_grpc.Server.Service]] = Fold(\n// self = Managed(self = zio.ZManaged$$anon$2@15f00ea8),\n// failure = Managed(self = zio.ZManaged$$anon$2@25f715d6),\n// success = Managed(self = zio.ZManaged$$anon$2@3fcc59f7)\n// )\n\nval ourApp = (UserDatabase.live ++ Console.any) >>>\n serverLayer\n// ourApp: zio.ZLayer[Any with Console, Throwable, Has[scalapb.zio_grpc.Server.Service]] = Fold(\n// self = ZipWithPar(\n// self = Managed(self = zio.ZManaged$$anon$2@519de9b2),\n// that = Managed(self = zio.ZManaged$$anon$2@64403fed),\n// f = zio.ZLayer$$Lambda$16816/0x0000000803ee6040@2bba085b\n// ),\n// failure = Managed(self = zio.ZManaged$$anon$2@54989ce3),\n// success = Fold(\n// self = Managed(self = zio.ZManaged$$anon$2@15f00ea8),\n// failure = Managed(self = zio.ZManaged$$anon$2@25f715d6),\n// success = Managed(self = zio.ZManaged$$anon$2@3fcc59f7)\n// )\n// )\n\nobject LayeredApp extends zio.App {\n def run(args: List[String]) = ourApp.build.useForever.exitCode\n}\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"serverLayer")," wraps around our service layer to produce a server. Then, ",(0,o.kt)("inlineCode",{parentName:"p"},"ourApp")," layer is constructed such that it takes ",(0,o.kt)("inlineCode",{parentName:"p"},"UserDatabase.live")," in conjuction to a passthrough layer for ",(0,o.kt)("inlineCode",{parentName:"p"},"Console")," to satisfy the two input requirements of ",(0,o.kt)("inlineCode",{parentName:"p"},"serverLayer"),". The outcome, ",(0,o.kt)("inlineCode",{parentName:"p"},"ourApp"),", is a ",(0,o.kt)("inlineCode",{parentName:"p"},"ZLayer")," that can produce a ",(0,o.kt)("inlineCode",{parentName:"p"},"Server")," from a ",(0,o.kt)("inlineCode",{parentName:"p"},"Console"),". In the ",(0,o.kt)("inlineCode",{parentName:"p"},"run")," method we build the layer and run it. Note that we are directly using a ",(0,o.kt)("inlineCode",{parentName:"p"},"zio.App")," rather than ",(0,o.kt)("inlineCode",{parentName:"p"},"ServerMain")," which does\nnot support this use case yet."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5ee1189a.fc66384a.js b/assets/js/5ee1189a.fc66384a.js new file mode 100644 index 000000000..288b04914 --- /dev/null +++ b/assets/js/5ee1189a.fc66384a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[66],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return m}});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=a.createContext({}),l=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=l(e.components);return a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(t),m=r,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||o;return t?a.createElement(f,i(i({ref:n},p),{},{components:t})):a.createElement(f,i({ref:n},p))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,i=new Array(o);i[0]=u;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:r,i[1]=s;for(var l=2;l IO[Status, User]")," to find the user."),(0,o.kt)("p",null,"For example, we can provide a function that returns an effect that always succeeds:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},'val fixedUserService =\n MyService.transformContextM((rc: RequestContext) => ZIO.succeed(User("foo")))\n// fixedUserService: ZSimpleService[Console, Has[RequestContext]] = myexample.testservice.ZioTestservice$ZSimpleService$$anon$6$$anon$7@5d50c6f9\n')),(0,o.kt)("p",null,"and we got our service, which still depends on an environment of type ",(0,o.kt)("inlineCode",{parentName:"p"},"Console"),", however the context is now ",(0,o.kt)("inlineCode",{parentName:"p"},"Has[RequestContext]")," so it can be bound to a gRPC server."),(0,o.kt)("h3",{id:"accessing-metadata"},"Accessing metadata"),(0,o.kt)("p",null,"Here is how we would extract a user from a metadata header:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},'import zio.IO\nimport scalapb.zio_grpc.{ServiceList, ServerMain}\n\nval UserKey = io.grpc.Metadata.Key.of(\n "user-key", io.grpc.Metadata.ASCII_STRING_MARSHALLER)\n// UserKey: io.grpc.Metadata.Key[String] = Key{name=\'user-key\'}\n\ndef findUser(rc: RequestContext): IO[Status, User] =\n rc.metadata.get(UserKey).flatMap {\n case Some(name) => IO.succeed(User(name))\n case _ => IO.fail(Status.UNAUTHENTICATED.withDescription("No access!"))\n }\n\nval rcService =\n MyService.transformContextM(findUser)\n// rcService: ZSimpleService[Console, Has[RequestContext]] = myexample.testservice.ZioTestservice$ZSimpleService$$anon$6$$anon$7@6e4166f6\n\nobject MyServer extends ServerMain {\n def services = ServiceList.add(rcService)\n}\n')),(0,o.kt)("h3",{id:"depending-on-a-service"},"Depending on a service"),(0,o.kt)("p",null,"A context transformation may introduce a dependency on another service. For example, you\nmay want to organize your code such that there is a ",(0,o.kt)("inlineCode",{parentName:"p"},"UserDatabase")," service that provides\na ",(0,o.kt)("inlineCode",{parentName:"p"},"fetchUser")," effect that retrieves users from a database. Here is how you can do this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"type UserDatabase = Has[UserDatabase.Service]\nobject UserDatabase {\n trait Service {\n def fetchUser(name: String): IO[Status, User]\n }\n\n // accessor\n def fetchUser(name: String): ZIO[UserDatabase, Status, User] =\n ZIO.accessM[UserDatabase](_.get.fetchUser(name))\n\n val live = zio.ZLayer.succeed(\n new Service {\n def fetchUser(name: String): IO[Status, User] =\n IO.succeed(User(name))\n })\n}\n")),(0,o.kt)("p",null,"Now,\nThe context transformation effect we apply may introduce an additional environmental dependency to our service. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"import zio.clock._\nimport zio.duration._\n\nval myServiceAuthWithDatabase =\n MyService.transformContextM {\n (rc: RequestContext) =>\n rc.metadata.get(UserKey)\n .someOrFail(Status.UNAUTHENTICATED)\n .flatMap(UserDatabase.fetchUser)\n }\n// myServiceAuthWithDatabase: ZSimpleService[Console with UserDatabase, Has[RequestContext]] = myexample.testservice.ZioTestservice$ZSimpleService$$anon$6$$anon$7@46db627e\n")),(0,o.kt)("p",null,"And now our service not only depends on a ",(0,o.kt)("inlineCode",{parentName:"p"},"Console"),", but also on a ",(0,o.kt)("inlineCode",{parentName:"p"},"UserDatabase"),"."),(0,o.kt)("h2",{id:"using-a-service-as-zlayer"},"Using a service as ZLayer"),(0,o.kt)("p",null,"We can turn our service into a ZLayer:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"val myServiceLive = myServiceAuthWithDatabase.toLayer\n// myServiceLive: zio.ZLayer[Console with UserDatabase, Nothing, Has[ZSimpleService[Any, Has[RequestContext]]]] = Managed(\n// self = zio.ZManaged$$anon$2@15f00ea8\n// )\n")),(0,o.kt)("p",null,"notice how the dependencies moved to the input side of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Layer")," and the resulting layer is of\ntype ",(0,o.kt)("inlineCode",{parentName:"p"},"ZSimpleService[Any, Has[RequestContext]]]"),", which means no environment is expected, and it assumes\na ",(0,o.kt)("inlineCode",{parentName:"p"},"Has[RequestContext]")," context. To use this layer in an app, we can wire it like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-scala"},"import scalapb.zio_grpc.ServerLayer\n\nval serverLayer =\n ServerLayer.fromServiceLayer(\n io.grpc.ServerBuilder.forPort(9000)\n )(myServiceLive)\n// serverLayer: zio.ZLayer[Console with UserDatabase, Throwable, Has[scalapb.zio_grpc.Server.Service]] = Fold(\n// self = Managed(self = zio.ZManaged$$anon$2@15f00ea8),\n// failure = Managed(self = zio.ZManaged$$anon$2@25f715d6),\n// success = Managed(self = zio.ZManaged$$anon$2@3fcc59f7)\n// )\n\nval ourApp = (UserDatabase.live ++ Console.any) >>>\n serverLayer\n// ourApp: zio.ZLayer[Any with Console, Throwable, Has[scalapb.zio_grpc.Server.Service]] = Fold(\n// self = ZipWithPar(\n// self = Managed(self = zio.ZManaged$$anon$2@519de9b2),\n// that = Managed(self = zio.ZManaged$$anon$2@64403fed),\n// f = zio.ZLayer$$Lambda$16816/0x0000000803ee6040@2bba085b\n// ),\n// failure = Managed(self = zio.ZManaged$$anon$2@54989ce3),\n// success = Fold(\n// self = Managed(self = zio.ZManaged$$anon$2@15f00ea8),\n// failure = Managed(self = zio.ZManaged$$anon$2@25f715d6),\n// success = Managed(self = zio.ZManaged$$anon$2@3fcc59f7)\n// )\n// )\n\nobject LayeredApp extends zio.App {\n def run(args: List[String]) = ourApp.build.useForever.exitCode\n}\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"serverLayer")," wraps around our service layer to produce a server. Then, ",(0,o.kt)("inlineCode",{parentName:"p"},"ourApp")," layer is constructed such that it takes ",(0,o.kt)("inlineCode",{parentName:"p"},"UserDatabase.live")," in conjuction to a passthrough layer for ",(0,o.kt)("inlineCode",{parentName:"p"},"Console")," to satisfy the two input requirements of ",(0,o.kt)("inlineCode",{parentName:"p"},"serverLayer"),". The outcome, ",(0,o.kt)("inlineCode",{parentName:"p"},"ourApp"),", is a ",(0,o.kt)("inlineCode",{parentName:"p"},"ZLayer")," that can produce a ",(0,o.kt)("inlineCode",{parentName:"p"},"Server")," from a ",(0,o.kt)("inlineCode",{parentName:"p"},"Console"),". In the ",(0,o.kt)("inlineCode",{parentName:"p"},"run")," method we build the layer and run it. Note that we are directly using a ",(0,o.kt)("inlineCode",{parentName:"p"},"zio.App")," rather than ",(0,o.kt)("inlineCode",{parentName:"p"},"ServerMain")," which does\nnot support this use case yet."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/77b5bd74.31a58916.js b/assets/js/77b5bd74.31a58916.js deleted file mode 100644 index 8df349897..000000000 --- a/assets/js/77b5bd74.31a58916.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[347],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.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,a=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=c(n),f=a,d=m["".concat(s,".").concat(f)]||m[f]||p[f]||i;return n?r.createElement(d,o(o({ref:t},u),{},{components:n})):r.createElement(d,o({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=c(r),f=a,d=m["".concat(s,".").concat(f)]||m[f]||p[f]||i;return r?n.createElement(d,o(o({ref:t},u),{},{components:r})):n.createElement(d,o({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=s(a),m=r,h=d["".concat(p,".").concat(m)]||d[m]||u[m]||l;return a?n.createElement(h,i(i({ref:t},c),{},{components:a})):n.createElement(h,i({ref:t},c))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,i=new Array(l);i[0]=d;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var s=2;s=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=s(a),m=r,h=d["".concat(p,".").concat(m)]||d[m]||u[m]||l;return a?n.createElement(h,i(i({ref:t},c),{},{components:a})):n.createElement(h,i({ref:t},c))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,i=new Array(l);i[0]=d;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var s=2;s=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),f=l(r),m=o,d=f["".concat(s,".").concat(m)]||f[m]||p[m]||a;return r?n.createElement(d,c(c({ref:t},u),{},{components:r})):n.createElement(d,c({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=f;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),f=l(r),m=o,d=f["".concat(s,".").concat(m)]||f[m]||p[m]||a;return r?n.createElement(d,c(c({ref:t},u),{},{components:r})):n.createElement(d,c({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=f;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),m=a,g=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return n?r.createElement(g,o(o({ref:t},p),{},{components:n})):r.createElement(g,o({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var s=2;s (sourceManaged in Compile).value / "scalapb",\n scalapb.zio_grpc.ZioCodeGenerator -> (sourceManaged in Compile).value / "scalapb"\n)\n\nlibraryDependencies ++= Seq(\n "io.grpc" % "grpc-netty" % "1.41.0",\n "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion\n)\n')),(0,i.kt)("p",null,"This configuration will set up the ScalaPB code generator alongside the ZIO gRPC code generator.\nUpon compilation, the source generator will process all proto files under ",(0,i.kt)("inlineCode",{parentName:"p"},"src/main/protobuf"),".\nThe ScalaPB generator will generate case classes for all messages as well as methods to serialize and deserialize those messages. The ZIO gRPC code generator will generate code as described in the ",(0,i.kt)("a",{parentName:"p",href:"/zio-grpc/docs/generated-code"},"generated code section"),"."),(0,i.kt)("h2",{id:"generating-code-using-scalapbc-cli"},"Generating code using ScalaPBC (CLI)"),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"See ",(0,i.kt)("a",{parentName:"mdxAdmonitionTitle",href:"http://scalapb.github.io/scalapbc.html"},"installation instructions for ScalaPBC"),".")),(0,i.kt)("p",null,"If you are using ScalaPBC to generate Scala code from the CLI, you can invoke the zio code generator like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"scalapbc \\\n--plugin-artifact=com.thesamet.scalapb.zio-grpc:protoc-gen-zio:0.5.0:default,classifier=unix,ext=sh,type=jar\\\n-- e2e/src/main/protobuf/service.proto --zio_out=/tmp/out --scala_out=grpc:/tmp/out \\\n-Ie2e/src/main/protobuf -Ithird_party -Iprotobuf\n")),(0,i.kt)("p",null,"You will need to add to your project the following libraries:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb::scalapb-runtime-grpc:0.11.8")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb.zio-grpc:zio-grpc-core:0.5.0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"io.grpc:grpc-netty:1.41.0"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9c997467.ce02b66a.js b/assets/js/9c997467.ce02b66a.js new file mode 100644 index 000000000..de0728836 --- /dev/null +++ b/assets/js/9c997467.ce02b66a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[335],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),m=a,g=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return n?r.createElement(g,o(o({ref:t},p),{},{components:n})):r.createElement(g,o({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var s=2;s (sourceManaged in Compile).value / "scalapb",\n scalapb.zio_grpc.ZioCodeGenerator -> (sourceManaged in Compile).value / "scalapb"\n)\n\nlibraryDependencies ++= Seq(\n "io.grpc" % "grpc-netty" % "1.41.0",\n "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion\n)\n')),(0,i.kt)("p",null,"This configuration will set up the ScalaPB code generator alongside the ZIO gRPC code generator.\nUpon compilation, the source generator will process all proto files under ",(0,i.kt)("inlineCode",{parentName:"p"},"src/main/protobuf"),".\nThe ScalaPB generator will generate case classes for all messages as well as methods to serialize and deserialize those messages. The ZIO gRPC code generator will generate code as described in the ",(0,i.kt)("a",{parentName:"p",href:"/zio-grpc/docs/0.5.x/generated-code"},"generated code section"),"."),(0,i.kt)("h2",{id:"generating-code-using-scalapbc-cli"},"Generating code using ScalaPBC (CLI)"),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"See ",(0,i.kt)("a",{parentName:"mdxAdmonitionTitle",href:"http://scalapb.github.io/scalapbc.html"},"installation instructions for ScalaPBC"),".")),(0,i.kt)("p",null,"If you are using ScalaPBC to generate Scala code from the CLI, you can invoke the zio code generator like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"scalapbc \\\n--plugin-artifact=com.thesamet.scalapb.zio-grpc:protoc-gen-zio:0.5.0:default,classifier=unix,ext=sh,type=jar\\\n-- e2e/src/main/protobuf/service.proto --zio_out=/tmp/out --scala_out=grpc:/tmp/out \\\n-Ie2e/src/main/protobuf -Ithird_party -Iprotobuf\n")),(0,i.kt)("p",null,"You will need to add to your project the following libraries:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb::scalapb-runtime-grpc:0.11.8")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb.zio-grpc:zio-grpc-core:0.5.0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"io.grpc:grpc-netty:1.41.0"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a9f25167.0fee2468.js b/assets/js/a9f25167.0fee2468.js deleted file mode 100644 index 2dc84c601..000000000 --- a/assets/js/a9f25167.0fee2468.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[922],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.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,a=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=c(n),f=a,d=m["".concat(s,".").concat(f)]||m[f]||p[f]||i;return n?r.createElement(d,o(o({ref:t},u),{},{components:n})):r.createElement(d,o({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.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,a=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=c(n),f=a,d=m["".concat(s,".").concat(f)]||m[f]||p[f]||i;return n?r.createElement(d,o(o({ref:t},u),{},{components:n})):r.createElement(d,o({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),c=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return i.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},p=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=a,h=p["".concat(s,".").concat(m)]||p[m]||u[m]||r;return n?i.createElement(h,o(o({ref:t},d),{},{components:n})):i.createElement(h,o({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c zio.IO[Status, CallOptions]): Service\n")),(0,r.kt)("p",null,"If you are using a client instance, the above methods are available to provide you with a new\nclient that has a modified ",(0,r.kt)("inlineCode",{parentName:"p"},"CallOptions")," effect. Making the copy of those clients is cheap and can\nbe safely done for each individual call:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"val clientManaged = ServiceNameClient.managed(channel)\n// clientManaged: Managed[Throwable, ServiceNameClient.ZService[Any, Any]] = zio.ZManaged$$anon$2@168ab14e\n\nval myAppLogic = for {\n res <- clientManaged.use(\n client =>\n client.withTimeoutMillis(3000).unary(Request())\n .mapError(_.asException)\n )\n} yield res\n// myAppLogic: ZIO[Any with Any, Throwable, Response] = zio.ZIO$FlatMap@2be1bc9f\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/aa547a5c.ee528685.js b/assets/js/aa547a5c.ee528685.js deleted file mode 100644 index b76fdf78b..000000000 --- a/assets/js/aa547a5c.ee528685.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[975],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return m}});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),c=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return i.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},p=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=a,h=p["".concat(s,".").concat(m)]||p[m]||u[m]||r;return n?i.createElement(h,o(o({ref:t},d),{},{components:n})):i.createElement(h,o({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c zio.IO[Status, CallOptions]): Service\n")),(0,r.kt)("p",null,"If you are using a client instance, the above methods are available to provide you with a new\nclient that has a modified ",(0,r.kt)("inlineCode",{parentName:"p"},"CallOptions")," effect. Making the copy of those clients is cheap and can\nbe safely done for each individual call:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"val clientManaged = ServiceNameClient.managed(channel)\n// clientManaged: Managed[Throwable, ServiceNameClient.ZService[Any, Any]] = zio.ZManaged$$anon$2@168ab14e\n\nval myAppLogic = for {\n res <- clientManaged.use(\n client =>\n client.withTimeoutMillis(3000).unary(Request())\n .mapError(_.asException)\n )\n} yield res\n// myAppLogic: ZIO[Any with Any, Throwable, Response] = zio.ZIO$FlatMap@2be1bc9f\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ab3b6cad.e0cec153.js b/assets/js/ab3b6cad.f83e1208.js similarity index 52% rename from assets/js/ab3b6cad.e0cec153.js rename to assets/js/ab3b6cad.f83e1208.js index f353e0e63..c1a836a58 100644 --- a/assets/js/ab3b6cad.e0cec153.js +++ b/assets/js/ab3b6cad.f83e1208.js @@ -1 +1 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[892],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(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({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},l={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,u=i(e,["components","mdxType","originalType","parentName"]),m=p(n),f=o,d=m["".concat(c,".").concat(f)]||m[f]||l[f]||a;return n?r.createElement(d,s(s({ref:t},u),{},{components:n})):r.createElement(d,s({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[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,s[1]=i;for(var p=2;p=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({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},l={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,u=i(e,["components","mdxType","originalType","parentName"]),m=p(n),f=o,d=m["".concat(c,".").concat(f)]||m[f]||l[f]||a;return n?r.createElement(d,s(s({ref:t},u),{},{components:n})):r.createElement(d,s({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[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,s[1]=i;for(var p=2;p=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),l=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=l(e.components);return a.createElement(s.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(t),m=r,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return t?a.createElement(h,o(o({ref:n},p),{},{components:t})):a.createElement(h,o({ref:n},p))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=u;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,o[1]=c;for(var l=2;l\n// )\n\n// myAppLogicNeedsEnv needs access to a ServiceNameClient. We turn it into\n// a self-contained effect (IO) by providing the layer to it:\nval myAppLogic1 = myAppLogicNeedsEnv.provideLayer(clientLayer)\n// myAppLogic1: ZIO[Any, Throwable, Unit] = DynamicNoBox(\n// trace = "repl.MdocSession.MdocApp.myAppLogic1(generated-code.md:46)",\n// update = 1L,\n// f = zio.ZIO$$$Lambda$12048/342507163@67eed504\n// )\n\nobject LayeredApp extends zio.ZIOAppDefault {\n def run: UIO[ExitCode] = myAppLogic1.exitCode\n}\n')),(0,i.kt)("p",null,"Here the application is broken to multiple value assignments so you can see the types.\nThe first effect ",(0,i.kt)("inlineCode",{parentName:"p"},"myAppLogicNeedsEnv")," uses accessor functions, which makes it depend on an environment of type ",(0,i.kt)("inlineCode",{parentName:"p"},"ServiceNameClient"),". It chains the ",(0,i.kt)("inlineCode",{parentName:"p"},"unary")," RPC with printing the result to the console, and hence the final inferred effect type is ",(0,i.kt)("inlineCode",{parentName:"p"},"ServiceNameClient"),". Once we provide our custom layer, the effect type is ",(0,i.kt)("inlineCode",{parentName:"p"},"ZEnv"),", which we can use with ZIO's ",(0,i.kt)("inlineCode",{parentName:"p"},"exit")," method."),(0,i.kt)("h3",{id:"using-a-scoped-client"},"Using a Scoped client"),(0,i.kt)("p",null,"As an alternative to using ZLayer, you can use the client as a scoped resource:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'import myexample.testservice.ZioTestservice.ServiceNameClient\nimport myexample.testservice.{Request, Response}\n\nval clientManaged = ServiceNameClient.scoped(channel)\n// clientManaged: ZIO[Scope, Throwable, ServiceNameClient] = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClient.scoped(ZioTestservice.scala:109)",\n// first = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClientWithResponseMetadata.scoped(ZioTestservice.scala:191)",\n// first = OnSuccess(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// first = Sync(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// eval = zio.ZIO$$$Lambda$11979/1227429986@5f26ea51\n// ),\n// successK = zio.ZIO$$$Lambda$11905/1122445729@13ee00f\n// ),\n// successK = zio.ZIO$$Lambda$11923/860077295@44b556c8\n// ),\n// successK = zio.ZIO$$Lambda$11923/860077295@5090a49b\n// )\n\nval myAppLogic = ZIO.scoped {\n clientManaged.flatMap { client =>\n for {\n res <- client.unary(Request())\n } yield res\n }\n}\n// myAppLogic: ZIO[Any, Throwable, Response] = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(generated-code.md:66)",\n// first = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(generated-code.md:66)",\n// first = Sync(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(generated-code.md:66)",\n// eval = zio.Scope$ReleaseMap$$$Lambda$11999/1041172792@66bc3232\n// ),\n// successK = zio.ZIO$$Lambda$11923/860077295@4ccdc93f\n// ),\n// successK = zio.ZIO$ScopedPartiallyApplied$$$Lambda$12001/1739244981@5d9a6357\n// )\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b484f81c.de35fec2.js b/assets/js/b484f81c.de35fec2.js new file mode 100644 index 000000000..3306e87ce --- /dev/null +++ b/assets/js/b484f81c.de35fec2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[622],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return m}});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),l=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=l(e.components);return a.createElement(s.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(t),m=r,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return t?a.createElement(h,o(o({ref:n},p),{},{components:t})):a.createElement(h,o({ref:n},p))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=u;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c.mdxType="string"==typeof e?e:r,o[1]=c;for(var l=2;l\n// )\n\n// myAppLogicNeedsEnv needs access to a ServiceNameClient. We turn it into\n// a self-contained effect (IO) by providing the layer to it:\nval myAppLogic1 = myAppLogicNeedsEnv.provideLayer(clientLayer)\n// myAppLogic1: ZIO[Any, Throwable, Unit] = DynamicNoBox(\n// trace = "repl.MdocSession.MdocApp.myAppLogic1(generated-code.md:46)",\n// update = 1L,\n// f = zio.ZIO$$$Lambda$12068/1537244774@960232a\n// )\n\nobject LayeredApp extends zio.ZIOAppDefault {\n def run: UIO[ExitCode] = myAppLogic1.exitCode\n}\n')),(0,i.kt)("p",null,"Here the application is broken to multiple value assignments so you can see the types.\nThe first effect ",(0,i.kt)("inlineCode",{parentName:"p"},"myAppLogicNeedsEnv")," uses accessor functions, which makes it depend on an environment of type ",(0,i.kt)("inlineCode",{parentName:"p"},"ServiceNameClient"),". It chains the ",(0,i.kt)("inlineCode",{parentName:"p"},"unary")," RPC with printing the result to the console, and hence the final inferred effect type is ",(0,i.kt)("inlineCode",{parentName:"p"},"ServiceNameClient"),". Once we provide our custom layer, the effect type is ",(0,i.kt)("inlineCode",{parentName:"p"},"ZEnv"),", which we can use with ZIO's ",(0,i.kt)("inlineCode",{parentName:"p"},"exit")," method."),(0,i.kt)("h3",{id:"using-a-scoped-client"},"Using a Scoped client"),(0,i.kt)("p",null,"As an alternative to using ZLayer, you can use the client as a scoped resource:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-scala"},'import myexample.testservice.ZioTestservice.ServiceNameClient\nimport myexample.testservice.{Request, Response}\n\nval clientManaged = ServiceNameClient.scoped(channel)\n// clientManaged: ZIO[Scope, Throwable, ServiceNameClient] = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClient.scoped(ZioTestservice.scala:109)",\n// first = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClientWithResponseMetadata.scoped(ZioTestservice.scala:191)",\n// first = OnSuccess(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// first = Sync(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// eval = zio.ZIO$$$Lambda$11999/1249366878@7103c7a9\n// ),\n// successK = zio.ZIO$$$Lambda$11925/1009964979@a4c55a1\n// ),\n// successK = zio.ZIO$$Lambda$11943/1788233188@677ae8dc\n// ),\n// successK = zio.ZIO$$Lambda$11943/1788233188@60cda0f8\n// )\n\nval myAppLogic = ZIO.scoped {\n clientManaged.flatMap { client =>\n for {\n res <- client.unary(Request())\n } yield res\n }\n}\n// myAppLogic: ZIO[Any, Throwable, Response] = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(generated-code.md:66)",\n// first = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(generated-code.md:66)",\n// first = Sync(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(generated-code.md:66)",\n// eval = zio.Scope$ReleaseMap$$$Lambda$12019/1343962133@541d5d\n// ),\n// successK = zio.ZIO$$Lambda$11943/1788233188@5cfffb6\n// ),\n// successK = zio.ZIO$ScopedPartiallyApplied$$$Lambda$12021/1002362138@d3ee556\n// )\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b5b67730.601a1665.js b/assets/js/b5b67730.601a1665.js deleted file mode 100644 index 0cc165c4b..000000000 --- a/assets/js/b5b67730.601a1665.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[344],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),m=a,g=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return n?r.createElement(g,o(o({ref:t},p),{},{components:n})):r.createElement(g,o({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var s=2;s (sourceManaged in Compile).value / "scalapb",\n scalapb.zio_grpc.ZioCodeGenerator -> (sourceManaged in Compile).value / "scalapb"\n)\n\nlibraryDependencies ++= Seq(\n "io.grpc" % "grpc-netty" % "1.50.1",\n "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion\n)\n')),(0,i.kt)("p",null,"This configuration will set up the ScalaPB code generator alongside the ZIO gRPC code generator.\nUpon compilation, the source generator will process all proto files under ",(0,i.kt)("inlineCode",{parentName:"p"},"src/main/protobuf"),".\nThe ScalaPB generator will generate case classes for all messages as well as methods to serialize and deserialize those messages. The ZIO gRPC code generator will generate code as described in the ",(0,i.kt)("a",{parentName:"p",href:"/zio-grpc/docs/next/generated-code"},"generated code section"),"."),(0,i.kt)("h2",{id:"generating-code-using-scalapbc-cli"},"Generating code using ScalaPBC (CLI)"),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"See ",(0,i.kt)("a",{parentName:"mdxAdmonitionTitle",href:"http://scalapb.github.io/scalapbc.html"},"installation instructions for ScalaPBC"),".")),(0,i.kt)("p",null,"If you are using ScalaPBC to generate Scala code from the CLI, you can invoke the zio code generator like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"scalapbc \\\n--plugin-artifact=com.thesamet.scalapb.zio-grpc:protoc-gen-zio:0.6.0-rc6:default,classifier=unix,ext=sh,type=jar\\\n-- e2e/src/main/protobuf/service.proto --zio_out=/tmp/out --scala_out=grpc:/tmp/out \\\n-Ie2e/src/main/protobuf -Ithird_party -Iprotobuf\n")),(0,i.kt)("p",null,"You will need to add to your project the following libraries:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb::scalapb-runtime-grpc:0.11.13")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb.zio-grpc:zio-grpc-core:0.6.0-rc6")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"io.grpc:grpc-netty:1.50.1"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b5b67730.fcf6fa54.js b/assets/js/b5b67730.fcf6fa54.js new file mode 100644 index 000000000..c7431e127 --- /dev/null +++ b/assets/js/b5b67730.fcf6fa54.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[344],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),m=a,g=d["".concat(c,".").concat(m)]||d[m]||u[m]||i;return n?r.createElement(g,o(o({ref:t},p),{},{components:n})):r.createElement(g,o({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var s=2;s (sourceManaged in Compile).value / "scalapb",\n scalapb.zio_grpc.ZioCodeGenerator -> (sourceManaged in Compile).value / "scalapb"\n)\n\nlibraryDependencies ++= Seq(\n "io.grpc" % "grpc-netty" % "1.50.1",\n "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion\n)\n')),(0,i.kt)("p",null,"This configuration will set up the ScalaPB code generator alongside the ZIO gRPC code generator.\nUpon compilation, the source generator will process all proto files under ",(0,i.kt)("inlineCode",{parentName:"p"},"src/main/protobuf"),".\nThe ScalaPB generator will generate case classes for all messages as well as methods to serialize and deserialize those messages. The ZIO gRPC code generator will generate code as described in the ",(0,i.kt)("a",{parentName:"p",href:"/zio-grpc/docs/generated-code"},"generated code section"),"."),(0,i.kt)("h2",{id:"generating-code-using-scalapbc-cli"},"Generating code using ScalaPBC (CLI)"),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"See ",(0,i.kt)("a",{parentName:"mdxAdmonitionTitle",href:"http://scalapb.github.io/scalapbc.html"},"installation instructions for ScalaPBC"),".")),(0,i.kt)("p",null,"If you are using ScalaPBC to generate Scala code from the CLI, you can invoke the zio code generator like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"scalapbc \\\n--plugin-artifact=com.thesamet.scalapb.zio-grpc:protoc-gen-zio:0.6.0-rc6:default,classifier=unix,ext=sh,type=jar\\\n-- e2e/src/main/protobuf/service.proto --zio_out=/tmp/out --scala_out=grpc:/tmp/out \\\n-Ie2e/src/main/protobuf -Ithird_party -Iprotobuf\n")),(0,i.kt)("p",null,"You will need to add to your project the following libraries:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb::scalapb-runtime-grpc:0.11.13")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"com.thesamet.scalapb.zio-grpc:zio-grpc-core:0.6.0-rc6")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"io.grpc:grpc-netty:1.50.1"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c445b332.ab06c409.js b/assets/js/c445b332.ab06c409.js new file mode 100644 index 000000000..2c1044684 --- /dev/null +++ b/assets/js/c445b332.ab06c409.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[869],{3905:function(e,n,t){t.d(n,{Zo:function(){return d},kt:function(){return m}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function s(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var o=a.createContext({}),l=function(e){var n=a.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},d=function(e){var n=l(e.components);return a.createElement(o.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,o=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),u=l(t),m=i,f=u["".concat(o,".").concat(m)]||u[m]||p[m]||r;return t?a.createElement(f,s(s({ref:n},d),{},{components:t})):a.createElement(f,s({ref:n},d))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,s=new Array(r);s[0]=u;var c={};for(var o in n)hasOwnProperty.call(n,o)&&(c[o]=n[o]);c.originalType=e,c.mdxType="string"==typeof e?e:i,s[1]=c;for(var l=2;l\n// )\n')),(0,r.kt)("h2",{id:"setting-timeout-for-each-request"},"Setting timeout for each request"),(0,r.kt)("p",null,"As in the previous example, assuming there is a client in the environment, we can set the timeout\nfor each request like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'ServiceNameClient.withTimeoutMillis(3000).unary(Request())\n// res0: ZIO[ServiceNameClient, io.grpc.StatusException, Response] = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameAccessors.unary(ZioTestservice.scala:77)",\n// first = Sync(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameAccessors.unary(ZioTestservice.scala:77)",\n// eval = zio.ZIO$ServiceWithZIOPartiallyApplied$$$Lambda$11934/1676433133@3c5b625b\n// ),\n// successK = zio.ZIO$$$Lambda$11925/1009964979@a4c55a1\n// )\n')),(0,r.kt)("p",null,"Clients provide (through the ",(0,r.kt)("inlineCode",{parentName:"p"},"GeneratedClient")," trait) a number of methods that makes it possible to\nspecify a deadline or a timeout for each request:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"// Provide a new absolute deadline\ndef withDeadline(deadline: Deadline): Service\n\n// Sets a new timeout for this service\ndef withTimeout(duration: zio.duration.Duration): Service\n\n// Sets a new timeout in millis\ndef withTimeoutMillis(millis: Long): Service\n\n// Replace the call options with the provided call options\ndef withCallOptions(callOptions: CallOptions): Service\n\n// update the CallOptions for this service\ndef mapCallOptions(f: CallOptions => CallOptions): Service\n\n// update the request Metadata for this service\ndef mapMetadataZIO(f: SafeMetadata => UIO[SafeMetadata]): Service\n")),(0,r.kt)("p",null,"If you are using a client instance, the above methods are available to provide you with a new\nclient that has a modified ",(0,r.kt)("inlineCode",{parentName:"p"},"CallOptions")," effect. Making the copy of those clients is cheap and can\nbe safely done for each individual call:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val clientScoped = ServiceNameClient.scoped(channel)\n// clientScoped: ZIO[Scope, Throwable, ServiceNameClient] = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClient.scoped(ZioTestservice.scala:109)",\n// first = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClientWithResponseMetadata.scoped(ZioTestservice.scala:191)",\n// first = OnSuccess(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// first = Sync(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// eval = zio.ZIO$$$Lambda$11999/1249366878@57aedd33\n// ),\n// successK = zio.ZIO$$$Lambda$11925/1009964979@a4c55a1\n// ),\n// successK = zio.ZIO$$Lambda$11943/1788233188@1130581e\n// ),\n// successK = zio.ZIO$$Lambda$11943/1788233188@50cfff4\n// )\n\nval myAppLogic = ZIO.scoped {\n clientScoped.flatMap { client =>\n for {\n res <- client\n .withTimeoutMillis(3000).unary(Request())\n } yield res\n }\n}\n// myAppLogic: ZIO[Any, Throwable, Response] = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(deadlines.md:57)",\n// first = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(deadlines.md:57)",\n// first = Sync(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(deadlines.md:57)",\n// eval = zio.Scope$ReleaseMap$$$Lambda$12019/1343962133@541d5d\n// ),\n// successK = zio.ZIO$$Lambda$11943/1788233188@677afeb6\n// ),\n// successK = zio.ZIO$ScopedPartiallyApplied$$$Lambda$12021/1002362138@7419baef\n// )\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c445b332.c8b07d76.js b/assets/js/c445b332.c8b07d76.js deleted file mode 100644 index 8c969db08..000000000 --- a/assets/js/c445b332.c8b07d76.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[869],{3905:function(e,n,t){t.d(n,{Zo:function(){return d},kt:function(){return m}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function s(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var o=a.createContext({}),l=function(e){var n=a.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},d=function(e){var n=l(e.components);return a.createElement(o.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,o=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),u=l(t),m=i,f=u["".concat(o,".").concat(m)]||u[m]||p[m]||r;return t?a.createElement(f,s(s({ref:n},d),{},{components:t})):a.createElement(f,s({ref:n},d))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,s=new Array(r);s[0]=u;var c={};for(var o in n)hasOwnProperty.call(n,o)&&(c[o]=n[o]);c.originalType=e,c.mdxType="string"==typeof e?e:i,s[1]=c;for(var l=2;l\n// )\n')),(0,r.kt)("h2",{id:"setting-timeout-for-each-request"},"Setting timeout for each request"),(0,r.kt)("p",null,"As in the previous example, assuming there is a client in the environment, we can set the timeout\nfor each request like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'ServiceNameClient.withTimeoutMillis(3000).unary(Request())\n// res0: ZIO[ServiceNameClient, io.grpc.StatusException, Response] = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameAccessors.unary(ZioTestservice.scala:77)",\n// first = Sync(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameAccessors.unary(ZioTestservice.scala:77)",\n// eval = zio.ZIO$ServiceWithZIOPartiallyApplied$$$Lambda$11914/467520303@7f5dc5d0\n// ),\n// successK = zio.ZIO$$$Lambda$11905/1122445729@13ee00f\n// )\n')),(0,r.kt)("p",null,"Clients provide (through the ",(0,r.kt)("inlineCode",{parentName:"p"},"GeneratedClient")," trait) a number of methods that makes it possible to\nspecify a deadline or a timeout for each request:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"// Provide a new absolute deadline\ndef withDeadline(deadline: Deadline): Service\n\n// Sets a new timeout for this service\ndef withTimeout(duration: zio.duration.Duration): Service\n\n// Sets a new timeout in millis\ndef withTimeoutMillis(millis: Long): Service\n\n// Replace the call options with the provided call options\ndef withCallOptions(callOptions: CallOptions): Service\n\n// update the CallOptions for this service\ndef mapCallOptions(f: CallOptions => CallOptions): Service\n\n// update the request Metadata for this service\ndef mapMetadataZIO(f: SafeMetadata => UIO[SafeMetadata]): Service\n")),(0,r.kt)("p",null,"If you are using a client instance, the above methods are available to provide you with a new\nclient that has a modified ",(0,r.kt)("inlineCode",{parentName:"p"},"CallOptions")," effect. Making the copy of those clients is cheap and can\nbe safely done for each individual call:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val clientScoped = ServiceNameClient.scoped(channel)\n// clientScoped: ZIO[Scope, Throwable, ServiceNameClient] = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClient.scoped(ZioTestservice.scala:109)",\n// first = OnSuccess(\n// trace = "myexample.testservice.ZioTestservice.ServiceNameClientWithResponseMetadata.scoped(ZioTestservice.scala:191)",\n// first = OnSuccess(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// first = Sync(\n// trace = "scalapb.zio_grpc.ZManagedChannel.apply(ZManagedChannel.scala:11)",\n// eval = zio.ZIO$$$Lambda$11979/1227429986@dfcfcc2\n// ),\n// successK = zio.ZIO$$$Lambda$11905/1122445729@13ee00f\n// ),\n// successK = zio.ZIO$$Lambda$11923/860077295@b9af818\n// ),\n// successK = zio.ZIO$$Lambda$11923/860077295@7948fc3a\n// )\n\nval myAppLogic = ZIO.scoped {\n clientScoped.flatMap { client =>\n for {\n res <- client\n .withTimeoutMillis(3000).unary(Request())\n } yield res\n }\n}\n// myAppLogic: ZIO[Any, Throwable, Response] = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(deadlines.md:57)",\n// first = OnSuccess(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(deadlines.md:57)",\n// first = Sync(\n// trace = "repl.MdocSession.MdocApp.myAppLogic(deadlines.md:57)",\n// eval = zio.Scope$ReleaseMap$$$Lambda$11999/1041172792@66bc3232\n// ),\n// successK = zio.ZIO$$Lambda$11923/860077295@775e1870\n// ),\n// successK = zio.ZIO$ScopedPartiallyApplied$$$Lambda$12001/1739244981@2bd874bb\n// )\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cdb862af.68f06069.js b/assets/js/cdb862af.68f06069.js deleted file mode 100644 index e2694df85..000000000 --- a/assets/js/cdb862af.68f06069.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[766],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function 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 l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(h,o(o({ref:t},p),{},{components:n})):a.createElement(h,o({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var u=2;u f.getLocation == point && f.name.nonEmpty)\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method takes the request (of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), and returns a ZIO\neffect that represents the work of computing the response. The value that is returned represents\na suspended effect: nothing actually happens until ZIO runtime\nultimately runs the effect. The type of the effect is ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO[ZEnv, StatusException, Feature]")," which means\nit is a computation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"can fail with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"StatusException")," (this type comes from grpc-java and contains gRPC status information)."),(0,r.kt)("li",{parentName:"ul"},"can succeed with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"Feature"),"."),(0,r.kt)("li",{parentName:"ul"},"requires an environment of type ",(0,r.kt)("inlineCode",{parentName:"li"},"ZEnv")," to run.")),(0,r.kt)("p",null,"In this case, our effect is built on top of a pure function ",(0,r.kt)("inlineCode",{parentName:"p"},"findFeature")," that returns ",(0,r.kt)("inlineCode",{parentName:"p"},"Some(feature)"),"\nif there is a feature in the database that corresponds to the given point, or ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," otherwise."),(0,r.kt)("p",null,"We use ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO.fromOption")," to turn the ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Feature]")," into an effect of type ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[Option[Nothing], Feature]"),"\nwhich means that it can either succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," or fail with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Nothing]")," (the only possible value of this type is ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," since there are no instances of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Nothing"),"). We\nthen use ",(0,r.kt)("inlineCode",{parentName:"p"},"mapError")," to map the case of an error to gRPC's ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND")," status."),(0,r.kt)("h3",{id:"server-side-streaming-rpc"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next let's look at one of our streaming RPCs. ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures")," is a server-side\nstreaming RPC, so we need to send back multiple ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s to our client."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def listFeatures(\n request: Rectangle\n): ZStream[Any, StatusException, Feature] = {\n val left = request.getLo.longitude min request.getHi.longitude\n val right = request.getLo.longitude max request.getHi.longitude\n val top = request.getLo.latitude max request.getHi.latitude\n val bottom = request.getLo.latitude min request.getHi.latitude\n\n ZStream.fromIterable(\n features.filter { feature =>\n val lat = feature.getLocation.latitude\n val lon = feature.getLocation.longitude\n lon >= left && lon <= right && lat >= bottom && lat <= top\n }\n )\n}\n")),(0,r.kt)("p",null,"Like the simple RPC, this method gets a request object (the ",(0,r.kt)("inlineCode",{parentName:"p"},"Rectangle")," in which\nour client wants to find ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s) and returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream[ZEnv, StatusException, Feature]"),", which represents an effectful stream that can produce, provided an environment of type\n",(0,r.kt)("inlineCode",{parentName:"p"},"ZEnv")," zero or more elements of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," and fail with a exception of type ",(0,r.kt)("inlineCode",{parentName:"p"},"StatusException"),"."),(0,r.kt)("p",null," This time, the stream does not need the environment and can not ever fail (since\nour database is a constant in the same process!)"),(0,r.kt)("p",null," We build the stream from a Scala collection we build by filtering through the features\nsequence. ZIO gRPC takes over streaming the response to the client when the stream\ngets executed."),(0,r.kt)("h3",{id:"client-side-streaming-rpc"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now let's look at something a little more complicated: the client-side streaming\nmethod ",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute()"),", where we get a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s from the client and\nreturn a single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," with information about their trip once the stream finishes."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def recordRoute(\n request: zio.stream.Stream[StatusException, Point]\n): ZIO[Any, StatusException, RouteSummary] =\n // Zips each element with the previous element, initially accompanied by None.\n request.zipWithPrevious\n .runFold(RouteSummary()) {\n case (summary, (maybePrevPoint, currentPoint)) =>\n // Compute the next status based on the current status.\n summary.copy(\n pointCount = summary.pointCount + 1,\n featureCount =\n summary.featureCount + (if (findFeature(currentPoint).isDefined) 1\n else 0),\n distance = summary.distance + maybePrevPoint\n .map(calcDistance(_, currentPoint))\n .getOrElse(0)\n )\n }\n .timed // returns a new effect that times the execution\n .map { case (duration, summary) =>\n summary.copy(elapsedTime = (duration.toMillis / 1000).toInt)\n }\n")),(0,r.kt)("p",null,"Here, our method gets a stream that is produced by the client. As you can see\nfrom the signature of this method, our goal would be to turn this stream into an\neffect that results in a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," contains the number of points, number of features on the trip, total distance passed, and the time it took. As this summary can be built iteratively we use fold, which takes the summary and new input to compute the next summary. Since we are\nadding up the distance between successive pair of points, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithPrevious"),"\nthat gives us a pair ",(0,r.kt)("inlineCode",{parentName:"p"},"(Option[Point], Point)")," where the left element represents the previous element in the stream (which is initially None)."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fold")," method gives us a ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[StatusException, RouteSummary]"),". Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"timed")," method we are getting a new ZIO effect that upon success gives us the a tuple ",(0,r.kt)("inlineCode",{parentName:"p"},"(zio.duration.Duration, RouteSummary)")," where the duration represents the time it took to process\nthe effect thus far. We then use ",(0,r.kt)("inlineCode",{parentName:"p"},"map")," to turn it back to a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," that contains the elapsed time in seconds."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def routeChat(\n request: zio.stream.Stream[StatusException, RouteNote]\n): ZStream[Any, StatusException, RouteNote] =\n request.flatMap { note =>\n // By using flatMap, we can map each RouteNote we receive to a stream with\n // the existing RouteNotes for that location, and those sub-streams are going\n // to get concatenated.\n // We start from an effect that updates the map with the new RouteNote,\n // and returns the notes associated with the location just before the update.\n val updateMapEffect: UIO[List[RouteNote]] =\n routeNotesRef.modify { routeNotes =>\n val messages = routeNotes.getOrElse(note.getLocation, Nil)\n (messages, routeNotes.updated(note.getLocation, note :: messages))\n }\n // We create a stream from the effect.\n ZStream.fromIterableZIO(updateMapEffect)\n }\n")),(0,r.kt)("p",null,"As with our client-side streaming example, we are getting a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s, except this time we are also returning a stream of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s. Although each side will always get the other's messages in the\norder they were written, both the client and server can read and write in any\norder \u2014 the streams operate completely independently."),(0,r.kt)("p",null,"In this example, we are using ",(0,r.kt)("inlineCode",{parentName:"p"},"flatMap")," on the incoming stream to map each input to a new\neffectful stream representing the notes that are available in that location. We are using ",(0,r.kt)("inlineCode",{parentName:"p"},"Ref#modify")," to mutate the collection of notes in the given location and return the list of notes available just prior to the update."),(0,r.kt)("h2",{id:"starting-the-server"},"Starting the server"),(0,r.kt)("p",null,"Once we've implemented all our methods, we also need to start up a gRPC server\nso that clients can actually use our service. The following snippet shows how we\ndo this for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide")," service:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'object RouteGuideServer extends ServerMain {\n override def port: Int = 8980\n\n val featuresDatabase = JsonFormat.fromJsonString[FeatureDatabase](\n Source.fromResource("route_guide_db.json").mkString\n )\n\n val createRouteGuide = for {\n routeNotes <- Ref.make(Map.empty[Point, List[RouteNote]])\n } yield new RouteGuideService(featuresDatabase.feature, routeNotes)\n\n def services: ServiceList[Any] =\n ServiceList.addZIO(createRouteGuide)\n}\n')),(0,r.kt)("p",null,"ZIO gRPC provides a base trait to quickly set up gRPC services with zero boilerplate."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"We override the port we are going to use (default is 9000)"),(0,r.kt)("li",{parentName:"ol"},"Create an effect that constructs an instance of our service (we need an effectful construction since\nour service constructor takes a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.Ref"),")"),(0,r.kt)("li",{parentName:"ol"},"Override ",(0,r.kt)("inlineCode",{parentName:"li"},"def services")," to return a ",(0,r.kt)("inlineCode",{parentName:"li"},"ServiceList")," that contains our service.")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," is meant to be used for simple applications. If you need to do more in your initialization, you can take a look at the source code of ",(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," and customize."),(0,r.kt)("h2",{id:"creating-the-client"},"Creating the client"),(0,r.kt)("p",null,"In this section, we'll look at creating a client for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide"),"\nservice. You can see our complete example client code in\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/scalapb/zio-grpc/blob/master/examples/src/main/scala/zio_grpc/examples/routeguide/RouteGuideClientApp.scala"},"RouteGuideClientApp.scala"),"."),(0,r.kt)("h3",{id:"instantiating-a-client"},"Instantiating a client"),(0,r.kt)("p",null,"To call service methods, we first need to create a client. There are two patterns\nto work with clients:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.managed")," to instantiate a client inside a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.ZManaged"),". Then through calling its ",(0,r.kt)("inlineCode",{parentName:"li"},"use")," method, the client can be accessed and method can be called on it."),(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.live")," to create a ",(0,r.kt)("inlineCode",{parentName:"li"},"ZLayer")," that can be used to provide a client as a singleton to our program through the environment. In that case, throughout the program we use accessor methods, defined statically in ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient")," that expect the client to be available in the environment.")),(0,r.kt)("p",null,"Throughout this tutorial, we will follow the second pattern. We create a ",(0,r.kt)("inlineCode",{parentName:"p"},"Layer")," that can provide a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val clientLayer: Layer[Throwable, RouteGuideClient] =\n RouteGuideClient.live(\n ZManagedChannel(\n ManagedChannelBuilder.forAddress("localhost", 8980).usePlaintext()\n )\n )\n')),(0,r.kt)("h3",{id:"calling-service-methods"},"Calling service methods"),(0,r.kt)("p",null,"Now let's look at how we call our service methods."),(0,r.kt)("p",null,"As described above, ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," contains accessor methods for each RPC\nthat return an effect or a stream that needs a client in the environment to be ran:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def getFeature(req: Point):\n ZIO[RouteGuideClient, StatusException, Feature]\n\ndef listFeatures(req: Rectangle):\n ZStream[RouteGuideClient, StatusException, Feature]\n\ndef recordRoute[R0](req: ZStream[R0, StatusException, Point]):\n ZIO[RouteGuideClient with R0, StatusException, RouteSummary]\n\ndef routeChat[R0](req: ZStream[R0, StatusException, RouteNote]):\n ZStream[RouteGuideClient with R0, StatusException, RouteNote]\n")),(0,r.kt)("h3",{id:"simple-rpc-1"},"Simple RPC"),(0,r.kt)("p",null,"Calling the simple RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"GetFeature")," on the static accessor stub is as\nstraightforward as instantiating a local effect:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def getFeature(\n lat: Int,\n lng: Int\n): ZIO[RouteGuideClient, StatusException, Unit] =\n (for {\n f <- RouteGuideClient.getFeature(Point(lat, lng))\n _ <- printLine(s"""Found feature called "${f.name}".""").orDie\n } yield ()).catchSome {\n case status if status.getStatus() == Status.NOT_FOUND =>\n printLine(s"Feature not found: ${status.toString()}").orDie\n }\n')),(0,r.kt)("p",null,"We create and populate a request protocol buffer object (in our case\n",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), pass it to the ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method on our accessor, and get\nback an effect that needs a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," environment. We chain\nthe response with a call to ",(0,r.kt)("inlineCode",{parentName:"p"},"printLine")," to print the result on the console,\nand we catch the ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND"),' response and print an error. All other errors\nare not handled at this level and will "bubble up" up to the program\'s ',(0,r.kt)("inlineCode",{parentName:"p"},"exitCode")," handler."),(0,r.kt)("h3",{id:"server-side-streaming-rpc-1"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next, let's look at a server-side streaming call to ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures"),", which\nreturns a stream of geographical ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'_ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach { case (feature, index) =>\n printLine(s"Result #${index + 1}: $feature")\n }\n')),(0,r.kt)("p",null,"Now ",(0,r.kt)("inlineCode",{parentName:"p"},"listFeatures")," returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream"),". We use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithIndex")," to get a stream\nwhere each of the original elements are accompanied with a zero-based index. We turn\nthis stream into a single effect that processes the entire stream by calling ",(0,r.kt)("inlineCode",{parentName:"p"},"foreach"),"\nand providing it with a function that maps each element into an effect. In this case,\nthe effect prints the feature."),(0,r.kt)("h3",{id:"client-side-streaming-rpc-1"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now for something a little more complicated: the client-side streaming method\n",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute"),", where we send a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s to the server and get back\na single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def recordRoute(numPoints: Int) =\n for {\n summary <- RouteGuideClient.recordRoute(\n ZStream\n .repeatZIO(\n nextIntBetween(0, features.size).map(features(_).getLocation)\n )\n .tap(p =>\n printLine(s"Visiting (${p.latitude}, ${p.longitude})").orDie\n )\n .schedule(Schedule.spaced(300.millis))\n .take(numPoints)\n )\n _ <- printLine(\n s"Finished trip with ${summary.pointCount} points. " +\n s"Passed ${summary.featureCount} features. " +\n s"Travelled ${summary.distance} meters. " +\n s"It took ${summary.elapsedTime} seconds."\n )\n } yield ()\n')),(0,r.kt)("p",null,"Here, we pass into ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute")," an effectful stream that randomly picks an element from the ",(0,r.kt)("inlineCode",{parentName:"p"},"features")," collection (a constant), and insert random delay between elements."),(0,r.kt)("p",null,"Like all the other accessor methods it's worth noting that no side effect happens upon calling ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute"),". The method returns immediately giving us an effect that represents sending this stream to the server. When the effect ultimately run it can succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," once the entire stream has been sent to the server."),(0,r.kt)("p",null,"In this example, we chain to this effect an effect to print the summary to the console."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc-1"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val routeChat =\n for {\n res <-\n RouteGuideClient\n .routeChat(\n ZStream(\n RouteNote(\n location = Some(Point(0, 0)),\n message = "First message"\n ),\n RouteNote(\n location = Some(Point(0, 10_000_000)),\n message = "Second Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 0)),\n message = "Third Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 10_000_000)),\n message = "Four Message"\n )\n ).tap { note =>\n printLine(\n s"""Sending message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n ).orDie\n }\n )\n .foreach { note =>\n printLine(\n s"""Got message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n )\n }\n } yield ()\n')),(0,r.kt)("p",null,"In this method, we both get and return a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\nRouteNotes. Here both streams execute independently at the same time. Although each side will always\nget the other's messages in the order they were written, both the client and\nserver can read and write in any order \u2014 the streams operate completely\nindependently."),(0,r.kt)("h3",{id:"providing-the-client-layer-into-the-application-logic"},"Providing the client layer into the application logic"),(0,r.kt)("p",null,"All the effects we created were dependent on a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," available in the environment. We earlier instantiated a ",(0,r.kt)("inlineCode",{parentName:"p"},"clientLayer"),", so we can provide it to our application logic at the top-level (the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val myAppLogic =\n for {\n // Looking for a valid feature\n _ <- getFeature(409146138, -746188906)\n // Looking for a missing feature\n _ <- getFeature(0, 0)\n\n // Calls listFeatures with a rectangle of interest. Prints\n // each response feature as it arrives.\n // start: listFeatures\n _ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach { case (feature, index) =>\n printLine(s"Result #${index + 1}: $feature")\n }\n // end: listFeatures\n\n _ <- recordRoute(10)\n\n _ <- routeChat\n } yield ()\n\nfinal def run =\n myAppLogic.provideLayer(clientLayer).exitCode\n')),(0,r.kt)("h2",{id:"try-it-out"},"Try it out!"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Run the server:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideServer"\n'))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"From another terminal, run the client:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideClientApp"\n')))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},'This document, "ZIO gRPC: Basics Tutorial", is a derivative of ',(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/docs/languages/java/basics/"},'"gRPC ',"\u2013",' Basics Tutorial"')," by ",(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/"},"gRPC Authors"),", used under ",(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0"),'. "ZIO gRPC: Basics Tutorial" is licensed under ',(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0")," by Nadav Samet.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cdb862af.fcfcd51f.js b/assets/js/cdb862af.fcfcd51f.js new file mode 100644 index 000000000..2366e9b09 --- /dev/null +++ b/assets/js/cdb862af.fcfcd51f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[766],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function 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 l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(h,o(o({ref:t},p),{},{components:n})):a.createElement(h,o({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,o[1]=s;for(var u=2;u f.getLocation == point && f.name.nonEmpty)\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method takes the request (of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), and returns a ZIO\neffect that represents the work of computing the response. The value that is returned represents\na suspended effect: nothing actually happens until ZIO runtime\nultimately runs the effect. The type of the effect is ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO[ZEnv, StatusException, Feature]")," which means\nit is a computation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"can fail with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"StatusException")," (this type comes from grpc-java and contains gRPC status information)."),(0,r.kt)("li",{parentName:"ul"},"can succeed with value of type ",(0,r.kt)("inlineCode",{parentName:"li"},"Feature"),"."),(0,r.kt)("li",{parentName:"ul"},"requires an environment of type ",(0,r.kt)("inlineCode",{parentName:"li"},"ZEnv")," to run.")),(0,r.kt)("p",null,"In this case, our effect is built on top of a pure function ",(0,r.kt)("inlineCode",{parentName:"p"},"findFeature")," that returns ",(0,r.kt)("inlineCode",{parentName:"p"},"Some(feature)"),"\nif there is a feature in the database that corresponds to the given point, or ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," otherwise."),(0,r.kt)("p",null,"We use ",(0,r.kt)("inlineCode",{parentName:"p"},"ZIO.fromOption")," to turn the ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Feature]")," into an effect of type ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[Option[Nothing], Feature]"),"\nwhich means that it can either succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," or fail with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Option[Nothing]")," (the only possible value of this type is ",(0,r.kt)("inlineCode",{parentName:"p"},"None")," since there are no instances of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Nothing"),"). We\nthen use ",(0,r.kt)("inlineCode",{parentName:"p"},"mapError")," to map the case of an error to gRPC's ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND")," status."),(0,r.kt)("h3",{id:"server-side-streaming-rpc"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next let's look at one of our streaming RPCs. ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures")," is a server-side\nstreaming RPC, so we need to send back multiple ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s to our client."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def listFeatures(\n request: Rectangle\n): ZStream[Any, StatusException, Feature] = {\n val left = request.getLo.longitude min request.getHi.longitude\n val right = request.getLo.longitude max request.getHi.longitude\n val top = request.getLo.latitude max request.getHi.latitude\n val bottom = request.getLo.latitude min request.getHi.latitude\n\n ZStream.fromIterable(\n features.filter { feature =>\n val lat = feature.getLocation.latitude\n val lon = feature.getLocation.longitude\n lon >= left && lon <= right && lat >= bottom && lat <= top\n }\n )\n}\n")),(0,r.kt)("p",null,"Like the simple RPC, this method gets a request object (the ",(0,r.kt)("inlineCode",{parentName:"p"},"Rectangle")," in which\nour client wants to find ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s) and returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream[ZEnv, StatusException, Feature]"),", which represents an effectful stream that can produce, provided an environment of type\n",(0,r.kt)("inlineCode",{parentName:"p"},"ZEnv")," zero or more elements of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature")," and fail with a exception of type ",(0,r.kt)("inlineCode",{parentName:"p"},"StatusException"),"."),(0,r.kt)("p",null," This time, the stream does not need the environment and can not ever fail (since\nour database is a constant in the same process!)"),(0,r.kt)("p",null," We build the stream from a Scala collection we build by filtering through the features\nsequence. ZIO gRPC takes over streaming the response to the client when the stream\ngets executed."),(0,r.kt)("h3",{id:"client-side-streaming-rpc"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now let's look at something a little more complicated: the client-side streaming\nmethod ",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute()"),", where we get a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s from the client and\nreturn a single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," with information about their trip once the stream finishes."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def recordRoute(\n request: zio.stream.Stream[StatusException, Point]\n): ZIO[Any, StatusException, RouteSummary] =\n // Zips each element with the previous element, initially accompanied by None.\n request.zipWithPrevious\n .runFold(RouteSummary()) {\n case (summary, (maybePrevPoint, currentPoint)) =>\n // Compute the next status based on the current status.\n summary.copy(\n pointCount = summary.pointCount + 1,\n featureCount =\n summary.featureCount + (if (findFeature(currentPoint).isDefined) 1\n else 0),\n distance = summary.distance + maybePrevPoint\n .map(calcDistance(_, currentPoint))\n .getOrElse(0)\n )\n }\n .timed // returns a new effect that times the execution\n .map { case (duration, summary) =>\n summary.copy(elapsedTime = (duration.toMillis / 1000).toInt)\n }\n")),(0,r.kt)("p",null,"Here, our method gets a stream that is produced by the client. As you can see\nfrom the signature of this method, our goal would be to turn this stream into an\neffect that results in a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," contains the number of points, number of features on the trip, total distance passed, and the time it took. As this summary can be built iteratively we use fold, which takes the summary and new input to compute the next summary. Since we are\nadding up the distance between successive pair of points, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithPrevious"),"\nthat gives us a pair ",(0,r.kt)("inlineCode",{parentName:"p"},"(Option[Point], Point)")," where the left element represents the previous element in the stream (which is initially None)."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fold")," method gives us a ",(0,r.kt)("inlineCode",{parentName:"p"},"IO[StatusException, RouteSummary]"),". Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"timed")," method we are getting a new ZIO effect that upon success gives us the a tuple ",(0,r.kt)("inlineCode",{parentName:"p"},"(zio.duration.Duration, RouteSummary)")," where the duration represents the time it took to process\nthe effect thus far. We then use ",(0,r.kt)("inlineCode",{parentName:"p"},"map")," to turn it back to a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," that contains the elapsed time in seconds."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def routeChat(\n request: zio.stream.Stream[StatusException, RouteNote]\n): ZStream[Any, StatusException, RouteNote] =\n request.flatMap { note =>\n // By using flatMap, we can map each RouteNote we receive to a stream with\n // the existing RouteNotes for that location, and those sub-streams are going\n // to get concatenated.\n // We start from an effect that updates the map with the new RouteNote,\n // and returns the notes associated with the location just before the update.\n val updateMapEffect: UIO[List[RouteNote]] =\n routeNotesRef.modify { routeNotes =>\n val messages = routeNotes.getOrElse(note.getLocation, Nil)\n (messages, routeNotes.updated(note.getLocation, note :: messages))\n }\n // We create a stream from the effect.\n ZStream.fromIterableZIO(updateMapEffect)\n }\n")),(0,r.kt)("p",null,"As with our client-side streaming example, we are getting a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s, except this time we are also returning a stream of\n",(0,r.kt)("inlineCode",{parentName:"p"},"RouteNote"),"s. Although each side will always get the other's messages in the\norder they were written, both the client and server can read and write in any\norder \u2014 the streams operate completely independently."),(0,r.kt)("p",null,"In this example, we are using ",(0,r.kt)("inlineCode",{parentName:"p"},"flatMap")," on the incoming stream to map each input to a new\neffectful stream representing the notes that are available in that location. We are using ",(0,r.kt)("inlineCode",{parentName:"p"},"Ref#modify")," to mutate the collection of notes in the given location and return the list of notes available just prior to the update."),(0,r.kt)("h2",{id:"starting-the-server"},"Starting the server"),(0,r.kt)("p",null,"Once we've implemented all our methods, we also need to start up a gRPC server\nso that clients can actually use our service. The following snippet shows how we\ndo this for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide")," service:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'object RouteGuideServer extends ServerMain {\n override def port: Int = 8980\n\n val featuresDatabase = JsonFormat.fromJsonString[FeatureDatabase](\n Source.fromResource("route_guide_db.json").mkString\n )\n\n val createRouteGuide = for {\n routeNotes <- Ref.make(Map.empty[Point, List[RouteNote]])\n } yield new RouteGuideService(featuresDatabase.feature, routeNotes)\n\n def services: ServiceList[Any] =\n ServiceList.addZIO(createRouteGuide)\n}\n')),(0,r.kt)("p",null,"ZIO gRPC provides a base trait to quickly set up gRPC services with zero boilerplate."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"We override the port we are going to use (default is 9000)"),(0,r.kt)("li",{parentName:"ol"},"Create an effect that constructs an instance of our service (we need an effectful construction since\nour service constructor takes a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.Ref"),")"),(0,r.kt)("li",{parentName:"ol"},"Override ",(0,r.kt)("inlineCode",{parentName:"li"},"def services")," to return a ",(0,r.kt)("inlineCode",{parentName:"li"},"ServiceList")," that contains our service.")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," is meant to be used for simple applications. If you need to do more in your initialization, you can take a look at the source code of ",(0,r.kt)("inlineCode",{parentName:"p"},"ServerMain")," and customize."),(0,r.kt)("h2",{id:"creating-the-client"},"Creating the client"),(0,r.kt)("p",null,"In this section, we'll look at creating a client for our ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuide"),"\nservice. You can see our complete example client code in\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/scalapb/zio-grpc/blob/master/examples/src/main/scala/zio_grpc/examples/routeguide/RouteGuideClientApp.scala"},"RouteGuideClientApp.scala"),"."),(0,r.kt)("h3",{id:"instantiating-a-client"},"Instantiating a client"),(0,r.kt)("p",null,"To call service methods, we first need to create a client. There are two patterns\nto work with clients:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.managed")," to instantiate a client inside a ",(0,r.kt)("inlineCode",{parentName:"li"},"zio.ZManaged"),". Then through calling its ",(0,r.kt)("inlineCode",{parentName:"li"},"use")," method, the client can be accessed and method can be called on it."),(0,r.kt)("li",{parentName:"ul"},"Use ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient.live")," to create a ",(0,r.kt)("inlineCode",{parentName:"li"},"ZLayer")," that can be used to provide a client as a singleton to our program through the environment. In that case, throughout the program we use accessor methods, defined statically in ",(0,r.kt)("inlineCode",{parentName:"li"},"RouteGuideClient")," that expect the client to be available in the environment.")),(0,r.kt)("p",null,"Throughout this tutorial, we will follow the second pattern. We create a ",(0,r.kt)("inlineCode",{parentName:"p"},"Layer")," that can provide a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val clientLayer: Layer[Throwable, RouteGuideClient] =\n RouteGuideClient.live(\n ZManagedChannel(\n ManagedChannelBuilder.forAddress("localhost", 8980).usePlaintext()\n )\n )\n')),(0,r.kt)("h3",{id:"calling-service-methods"},"Calling service methods"),(0,r.kt)("p",null,"Now let's look at how we call our service methods."),(0,r.kt)("p",null,"As described above, ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," contains accessor methods for each RPC\nthat return an effect or a stream that needs a client in the environment to be ran:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},"def getFeature(req: Point):\n ZIO[RouteGuideClient, StatusException, Feature]\n\ndef listFeatures(req: Rectangle):\n ZStream[RouteGuideClient, StatusException, Feature]\n\ndef recordRoute[R0](req: ZStream[R0, StatusException, Point]):\n ZIO[RouteGuideClient with R0, StatusException, RouteSummary]\n\ndef routeChat[R0](req: ZStream[R0, StatusException, RouteNote]):\n ZStream[RouteGuideClient with R0, StatusException, RouteNote]\n")),(0,r.kt)("h3",{id:"simple-rpc-1"},"Simple RPC"),(0,r.kt)("p",null,"Calling the simple RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"GetFeature")," on the static accessor stub is as\nstraightforward as instantiating a local effect:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def getFeature(\n lat: Int,\n lng: Int\n): ZIO[RouteGuideClient, StatusException, Unit] =\n (for {\n f <- RouteGuideClient.getFeature(Point(lat, lng))\n _ <- printLine(s"""Found feature called "${f.name}".""").orDie\n } yield ()).catchSome {\n case status if status.getStatus() == Status.NOT_FOUND =>\n printLine(s"Feature not found: ${status.toString()}").orDie\n }\n')),(0,r.kt)("p",null,"We create and populate a request protocol buffer object (in our case\n",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"), pass it to the ",(0,r.kt)("inlineCode",{parentName:"p"},"getFeature()")," method on our accessor, and get\nback an effect that needs a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," environment. We chain\nthe response with a call to ",(0,r.kt)("inlineCode",{parentName:"p"},"printLine")," to print the result on the console,\nand we catch the ",(0,r.kt)("inlineCode",{parentName:"p"},"NOT_FOUND"),' response and print an error. All other errors\nare not handled at this level and will "bubble up" up to the program\'s ',(0,r.kt)("inlineCode",{parentName:"p"},"exitCode")," handler."),(0,r.kt)("h3",{id:"server-side-streaming-rpc-1"},"Server-side streaming RPC"),(0,r.kt)("p",null,"Next, let's look at a server-side streaming call to ",(0,r.kt)("inlineCode",{parentName:"p"},"ListFeatures"),", which\nreturns a stream of geographical ",(0,r.kt)("inlineCode",{parentName:"p"},"Feature"),"s:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'_ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach { case (feature, index) =>\n printLine(s"Result #${index + 1}: $feature")\n }\n')),(0,r.kt)("p",null,"Now ",(0,r.kt)("inlineCode",{parentName:"p"},"listFeatures")," returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"ZStream"),". We use ",(0,r.kt)("inlineCode",{parentName:"p"},"zipWithIndex")," to get a stream\nwhere each of the original elements are accompanied with a zero-based index. We turn\nthis stream into a single effect that processes the entire stream by calling ",(0,r.kt)("inlineCode",{parentName:"p"},"foreach"),"\nand providing it with a function that maps each element into an effect. In this case,\nthe effect prints the feature."),(0,r.kt)("h3",{id:"client-side-streaming-rpc-1"},"Client-side streaming RPC"),(0,r.kt)("p",null,"Now for something a little more complicated: the client-side streaming method\n",(0,r.kt)("inlineCode",{parentName:"p"},"RecordRoute"),", where we send a stream of ",(0,r.kt)("inlineCode",{parentName:"p"},"Point"),"s to the server and get back\na single ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'def recordRoute(numPoints: Int) =\n for {\n summary <- RouteGuideClient.recordRoute(\n ZStream\n .repeatZIO(\n nextIntBetween(0, features.size).map(features(_).getLocation)\n )\n .tap(p =>\n printLine(s"Visiting (${p.latitude}, ${p.longitude})").orDie\n )\n .schedule(Schedule.spaced(300.millis))\n .take(numPoints)\n )\n _ <- printLine(\n s"Finished trip with ${summary.pointCount} points. " +\n s"Passed ${summary.featureCount} features. " +\n s"Travelled ${summary.distance} meters. " +\n s"It took ${summary.elapsedTime} seconds."\n )\n } yield ()\n')),(0,r.kt)("p",null,"Here, we pass into ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute")," an effectful stream that randomly picks an element from the ",(0,r.kt)("inlineCode",{parentName:"p"},"features")," collection (a constant), and insert random delay between elements."),(0,r.kt)("p",null,"Like all the other accessor methods it's worth noting that no side effect happens upon calling ",(0,r.kt)("inlineCode",{parentName:"p"},"recordRoute"),". The method returns immediately giving us an effect that represents sending this stream to the server. When the effect ultimately run it can succeed with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteSummary")," once the entire stream has been sent to the server."),(0,r.kt)("p",null,"In this example, we chain to this effect an effect to print the summary to the console."),(0,r.kt)("h3",{id:"bidirectional-streaming-rpc-1"},"Bidirectional streaming RPC"),(0,r.kt)("p",null,"Finally, let's look at our bidirectional streaming RPC ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteChat()"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val routeChat =\n for {\n res <-\n RouteGuideClient\n .routeChat(\n ZStream(\n RouteNote(\n location = Some(Point(0, 0)),\n message = "First message"\n ),\n RouteNote(\n location = Some(Point(0, 10_000_000)),\n message = "Second Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 0)),\n message = "Third Message"\n ),\n RouteNote(\n location = Some(Point(10_000_000, 10_000_000)),\n message = "Four Message"\n )\n ).tap { note =>\n printLine(\n s"""Sending message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n ).orDie\n }\n )\n .foreach { note =>\n printLine(\n s"""Got message "${note.message}" at ${note.getLocation.latitude}, ${note.getLocation.longitude}"""\n )\n }\n } yield ()\n')),(0,r.kt)("p",null,"In this method, we both get and return a ",(0,r.kt)("inlineCode",{parentName:"p"},"Stream")," of\nRouteNotes. Here both streams execute independently at the same time. Although each side will always\nget the other's messages in the order they were written, both the client and\nserver can read and write in any order \u2014 the streams operate completely\nindependently."),(0,r.kt)("h3",{id:"providing-the-client-layer-into-the-application-logic"},"Providing the client layer into the application logic"),(0,r.kt)("p",null,"All the effects we created were dependent on a ",(0,r.kt)("inlineCode",{parentName:"p"},"RouteGuideClient")," available in the environment. We earlier instantiated a ",(0,r.kt)("inlineCode",{parentName:"p"},"clientLayer"),", so we can provide it to our application logic at the top-level (the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-scala"},'val myAppLogic =\n for {\n // Looking for a valid feature\n _ <- getFeature(409146138, -746188906)\n // Looking for a missing feature\n _ <- getFeature(0, 0)\n\n // Calls listFeatures with a rectangle of interest. Prints\n // each response feature as it arrives.\n // start: listFeatures\n _ <-\n RouteGuideClient\n .listFeatures(\n Rectangle(\n lo = Some(Point(400000000, -750000000)),\n hi = Some(Point(420000000, -730000000))\n )\n )\n .zipWithIndex\n .foreach { case (feature, index) =>\n printLine(s"Result #${index + 1}: $feature")\n }\n // end: listFeatures\n\n _ <- recordRoute(10)\n\n _ <- routeChat\n } yield ()\n\nfinal def run =\n myAppLogic.provideLayer(clientLayer).exitCode\n')),(0,r.kt)("h2",{id:"try-it-out"},"Try it out!"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Run the server:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideServer"\n'))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"From another terminal, run the client:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'sbt "runMain zio_grpc.examples.routeguide.RouteGuideClientApp"\n')))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},'This document, "ZIO gRPC: Basics Tutorial", is a derivative of ',(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/docs/languages/java/basics/"},'"gRPC ',"\u2013",' Basics Tutorial"')," by ",(0,r.kt)("a",{parentName:"p",href:"https://grpc.io/"},"gRPC Authors"),", used under ",(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0"),'. "ZIO gRPC: Basics Tutorial" is licensed under ',(0,r.kt)("a",{parentName:"p",href:"https://creativecommons.org/licenses/by/4.0"},"CC-BY-4.0")," by Nadav Samet.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d066d984.08a9c1ac.js b/assets/js/d066d984.08a9c1ac.js deleted file mode 100644 index 02a0e4dd2..000000000 --- a/assets/js/d066d984.08a9c1ac.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[42],{5098:function(e){e.exports=JSON.parse('{"pluginId":"default","version":"0.5.x","label":"0.5.x","banner":null,"badge":true,"noIndex":false,"className":"docs-version-0.5.x","isLast":true,"docsSidebars":{"version-0.5.x/someSidebar":[{"collapsed":false,"type":"category","label":"Getting Started","items":[{"type":"link","label":"Introduction","href":"/zio-grpc/docs/","docId":"intro"},{"type":"link","label":"Quick Start","href":"/zio-grpc/docs/quickstart","docId":"quickstart"},{"type":"link","label":"Basics Tutorial","href":"/zio-grpc/docs/basics","docId":"basics"}],"collapsible":false},{"collapsed":false,"type":"category","label":"Guides","items":[{"type":"link","label":"Installing","href":"/zio-grpc/docs/installation","docId":"installation"},{"type":"link","label":"Generated code","href":"/zio-grpc/docs/generated-code","docId":"generated-code"},{"type":"link","label":"Context and Dependencies","href":"/zio-grpc/docs/context","docId":"context"},{"type":"link","label":"Decorating services","href":"/zio-grpc/docs/decorating","docId":"decorating"},{"type":"link","label":"ZIO gRPC and Deadlines","href":"/zio-grpc/docs/deadlines","docId":"deadlines"},{"type":"link","label":"Scala.js","href":"/zio-grpc/docs/scala.js","docId":"scala.js"},{"type":"link","label":"Backpressure","href":"/zio-grpc/docs/backpressure","docId":"backpressure"}],"collapsible":false}]},"docs":{"backpressure":{"id":"backpressure","title":"Backpressure","description":"From version 0.5.3 onwards, zio-grpc provides backpressure support for server","sidebar":"version-0.5.x/someSidebar"},"basics":{"id":"basics","title":"Basics Tutorial","description":"A basic tutorial introduction to ZIO gRPC","sidebar":"version-0.5.x/someSidebar"},"context":{"id":"context","title":"Context and Dependencies","description":"When implementing a server, ZIO gRPC allows you to specify that your service","sidebar":"version-0.5.x/someSidebar"},"deadlines":{"id":"deadlines","title":"ZIO gRPC and Deadlines","description":"Setting deadlines with ZIO gRPC","sidebar":"version-0.5.x/someSidebar"},"decorating":{"id":"decorating","title":"Decorating services","description":"Transformation of an effect or a stream.","sidebar":"version-0.5.x/someSidebar"},"generated-code":{"id":"generated-code","title":"Generated Code Reference","description":"Packages and code location","sidebar":"version-0.5.x/someSidebar"},"installation":{"id":"installation","title":"Installing ZIO gRPC","description":"Determining the right version","sidebar":"version-0.5.x/someSidebar"},"intro":{"id":"intro","title":"Introduction","description":"ZIO-gRPC lets you write purely functional gRPC servers and clients. It is built on top of ZIO, a library for asynchronous and concurrent functional programming in Scala.","sidebar":"version-0.5.x/someSidebar"},"quickstart":{"id":"quickstart","title":"Quick Start","description":"This guide gets you started with ZIO gRPC with a simple working example.","sidebar":"version-0.5.x/someSidebar"},"scala.js":{"id":"scala.js","title":"Using with Scala.js","description":"More information will come here soon. In the mean time, take a look at","sidebar":"version-0.5.x/someSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/d066d984.f490eff7.js b/assets/js/d066d984.f490eff7.js new file mode 100644 index 000000000..40d5c79d4 --- /dev/null +++ b/assets/js/d066d984.f490eff7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[42],{5098:function(e){e.exports=JSON.parse('{"pluginId":"default","version":"0.5.x","label":"0.5.x","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.5.x","isLast":false,"docsSidebars":{"version-0.5.x/someSidebar":[{"collapsed":false,"type":"category","label":"Getting Started","items":[{"type":"link","label":"Introduction","href":"/zio-grpc/docs/0.5.x/","docId":"intro"},{"type":"link","label":"Quick Start","href":"/zio-grpc/docs/0.5.x/quickstart","docId":"quickstart"},{"type":"link","label":"Basics Tutorial","href":"/zio-grpc/docs/0.5.x/basics","docId":"basics"}],"collapsible":false},{"collapsed":false,"type":"category","label":"Guides","items":[{"type":"link","label":"Installing","href":"/zio-grpc/docs/0.5.x/installation","docId":"installation"},{"type":"link","label":"Generated code","href":"/zio-grpc/docs/0.5.x/generated-code","docId":"generated-code"},{"type":"link","label":"Context and Dependencies","href":"/zio-grpc/docs/0.5.x/context","docId":"context"},{"type":"link","label":"Decorating services","href":"/zio-grpc/docs/0.5.x/decorating","docId":"decorating"},{"type":"link","label":"ZIO gRPC and Deadlines","href":"/zio-grpc/docs/0.5.x/deadlines","docId":"deadlines"},{"type":"link","label":"Scala.js","href":"/zio-grpc/docs/0.5.x/scala.js","docId":"scala.js"},{"type":"link","label":"Backpressure","href":"/zio-grpc/docs/0.5.x/backpressure","docId":"backpressure"}],"collapsible":false}]},"docs":{"backpressure":{"id":"backpressure","title":"Backpressure","description":"From version 0.5.3 onwards, zio-grpc provides backpressure support for server","sidebar":"version-0.5.x/someSidebar"},"basics":{"id":"basics","title":"Basics Tutorial","description":"A basic tutorial introduction to ZIO gRPC","sidebar":"version-0.5.x/someSidebar"},"context":{"id":"context","title":"Context and Dependencies","description":"When implementing a server, ZIO gRPC allows you to specify that your service","sidebar":"version-0.5.x/someSidebar"},"deadlines":{"id":"deadlines","title":"ZIO gRPC and Deadlines","description":"Setting deadlines with ZIO gRPC","sidebar":"version-0.5.x/someSidebar"},"decorating":{"id":"decorating","title":"Decorating services","description":"Transformation of an effect or a stream.","sidebar":"version-0.5.x/someSidebar"},"generated-code":{"id":"generated-code","title":"Generated Code Reference","description":"Packages and code location","sidebar":"version-0.5.x/someSidebar"},"installation":{"id":"installation","title":"Installing ZIO gRPC","description":"Determining the right version","sidebar":"version-0.5.x/someSidebar"},"intro":{"id":"intro","title":"Introduction","description":"ZIO-gRPC lets you write purely functional gRPC servers and clients. It is built on top of ZIO, a library for asynchronous and concurrent functional programming in Scala.","sidebar":"version-0.5.x/someSidebar"},"quickstart":{"id":"quickstart","title":"Quick Start","description":"This guide gets you started with ZIO gRPC with a simple working example.","sidebar":"version-0.5.x/someSidebar"},"scala.js":{"id":"scala.js","title":"Using with Scala.js","description":"More information will come here soon. In the mean time, take a look at","sidebar":"version-0.5.x/someSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/e367d32b.9c3c66f7.js b/assets/js/e367d32b.9c3c66f7.js deleted file mode 100644 index b07c6a55c..000000000 --- a/assets/js/e367d32b.9c3c66f7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[539],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return u}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var c=a.createContext({}),s=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=s(e.components);return a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=s(t),u=i,h=m["".concat(c,".").concat(u)]||m[u]||d[u]||r;return t?a.createElement(h,o(o({ref:n},p),{},{components:t})):a.createElement(h,o({ref:n},p))}));function u(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=m;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s\n client.unary(Request()).mapError(_.asException)\n )\n} yield res\n// myAppLogic: ZIO[Any with Any, Throwable, Response] = zio.ZIO$FlatMap@1a4cd330\n")),(0,r.kt)("p",null,"Since the service acquistion (through the ZManaged) can fail with a ",(0,r.kt)("inlineCode",{parentName:"p"},"Throwable"),", and the RPC effects of ZIO gRPC can fail with ",(0,r.kt)("inlineCode",{parentName:"p"},"Status")," (which is not a subtype of ",(0,r.kt)("inlineCode",{parentName:"p"},"Throwable"),"), we use ",(0,r.kt)("inlineCode",{parentName:"p"},"mapError")," to map the RPC error to a ",(0,r.kt)("inlineCode",{parentName:"p"},"StatusException"),". This way, the resulting effect can fail with a ",(0,r.kt)("inlineCode",{parentName:"p"},"Throwable"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e367d32b.a1038f3c.js b/assets/js/e367d32b.a1038f3c.js new file mode 100644 index 000000000..d69d55b93 --- /dev/null +++ b/assets/js/e367d32b.a1038f3c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[539],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return u}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var c=a.createContext({}),s=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=s(e.components);return a.createElement(c.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=s(t),u=i,h=m["".concat(c,".").concat(u)]||m[u]||d[u]||r;return t?a.createElement(h,o(o({ref:n},p),{},{components:t})):a.createElement(h,o({ref:n},p))}));function u(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=m;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var s=2;s\n client.unary(Request()).mapError(_.asException)\n )\n} yield res\n// myAppLogic: ZIO[Any with Any, Throwable, Response] = zio.ZIO$FlatMap@1a4cd330\n")),(0,r.kt)("p",null,"Since the service acquistion (through the ZManaged) can fail with a ",(0,r.kt)("inlineCode",{parentName:"p"},"Throwable"),", and the RPC effects of ZIO gRPC can fail with ",(0,r.kt)("inlineCode",{parentName:"p"},"Status")," (which is not a subtype of ",(0,r.kt)("inlineCode",{parentName:"p"},"Throwable"),"), we use ",(0,r.kt)("inlineCode",{parentName:"p"},"mapError")," to map the RPC error to a ",(0,r.kt)("inlineCode",{parentName:"p"},"StatusException"),". This way, the resulting effect can fail with a ",(0,r.kt)("inlineCode",{parentName:"p"},"Throwable"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/fbee2072.8c4d8ec3.js b/assets/js/fbee2072.aa9261f1.js similarity index 69% rename from assets/js/fbee2072.8c4d8ec3.js rename to assets/js/fbee2072.aa9261f1.js index 75f7ffabe..7e527a4cd 100644 --- a/assets/js/fbee2072.8c4d8ec3.js +++ b/assets/js/fbee2072.aa9261f1.js @@ -1 +1 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[491],{3905:function(e,r,t){t.d(r,{Zo:function(){return u},kt:function(){return f}});var n=t(7294);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=n.createContext({}),p=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},u=function(e){var r=p(e.components);return n.createElement(c.Provider,{value:r},e.children)},l={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=p(t),f=o,m=d["".concat(c,".").concat(f)]||d[f]||l[f]||a;return t?n.createElement(m,s(s({ref:r},u),{},{components:t})):n.createElement(m,s({ref:r},u))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=d;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=n.createContext({}),p=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},u=function(e){var r=p(e.components);return n.createElement(c.Provider,{value:r},e.children)},l={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=p(t),f=o,m=d["".concat(c,".").concat(f)]||d[f]||l[f]||a;return t?n.createElement(m,s(s({ref:r},u),{},{components:t})):n.createElement(m,s({ref:r},u))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=d;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i.mdxType="string"==typeof e?e:o,s[1]=i;for(var p=2;p1?t-1:0),r=1;r\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(/0)&&(F.current.unobserve(e),F.current.disconnect(),null!=L&&window.docusaurus.prefetch(L))}))})),F.current.observe(e))},to:L},g&&{isActive:y,activeClassName:b}))}var g=o.forwardRef(m)},1875:function(e,t){"use strict";t.Z=function(){return null}},5999:function(e,t,n){"use strict";n.d(t,{Z:function(){return u},I:function(){return l}});var r=n(7294);function a(e,t){var n=e.split(/(\{\w+\})/).map((function(e,n){if(n%2==1){var r=null==t?void 0:t[e.slice(1,-1)];if(void 0!==r)return r}return e}));return n.some((function(e){return(0,r.isValidElement)(e)}))?n.map((function(e,t){return(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e})).filter((function(e){return""!==e})):n.join("")}var o=n(7529);function i(e){var t,n,r=e.id,a=e.message;if(void 0===r&&void 0===a)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return null!=(t=null!=(n=o[null!=r?r:a])?n:a)?t:r}function l(e,t){return a(i({message:e.message,id:e.id}),t)}function u(e){var t=e.children,n=e.id,o=e.values;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");var l=i({message:t,id:n});return r.createElement(r.Fragment,null,a(l,o))}},9935:function(e,t,n){"use strict";n.d(t,{m:function(){return r}});var r="default"},3919:function(e,t,n){"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:function(){return a},b:function(){return r}})},4996:function(e,t,n){"use strict";n.d(t,{C:function(){return o},Z:function(){return i}});var r=n(2263),a=n(3919);function o(){var e=(0,r.Z)().siteConfig,t=e.baseUrl,n=e.url;return{withBaseUrl:function(e,r){return function(e,t,n,r){var o=void 0===r?{}:r,i=o.forcePrependBaseUrl,l=void 0!==i&&i,u=o.absolute,s=void 0!==u&&u;if(!n||n.startsWith("#")||(0,a.b)(n))return n;if(l)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;var c=n.startsWith(t)?n:t+n.replace(/^\//,"");return s?e+c:c}(n,t,e,r)}}}function i(e,t){return void 0===t&&(t={}),(0,o().withBaseUrl)(e,t)}},2263:function(e,t,n){"use strict";n.d(t,{Z:function(){return o}});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},2389:function(e,t,n){"use strict";n.d(t,{Z:function(){return o}});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},9670:function(e,t,n){"use strict";n.d(t,{Z:function(){return r}});function r(e){var t={};return function e(n,r){Object.entries(n).forEach((function(n){var a,o=n[0],i=n[1],l=r?r+"."+o:o;"object"==typeof(a=i)&&a&&Object.keys(a).length>0?e(i,l):t[l]=i}))}(e),t}},226:function(e,t,n){"use strict";n.d(t,{_:function(){return a},z:function(){return o}});var r=n(7294),a=r.createContext(null);function o(e){var t=e.children,n=e.value,o=r.useContext(a),i=(0,r.useMemo)((function(){return function(e){var t=e.parent,n=e.value;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}var r=Object.assign({},t.data,null==n?void 0:n.data);return{plugin:t.plugin,data:r}}({parent:o,value:n})}),[o,n]);return r.createElement(a.Provider,{value:i},t)}},143:function(e,t,n){"use strict";n.d(t,{Iw:function(){return g},gA:function(){return f},_r:function(){return c},Jo:function(){return h},zh:function(){return d},yW:function(){return m},gB:function(){return p}});var r=n(6550),a=n(2263),o=n(9935);function i(e,t){void 0===t&&(t={});var n=(0,a.Z)().globalData[e];if(!n&&t.failfast)throw new Error('Docusaurus plugin global data not found for "'+e+'" plugin.');return n}var l=function(e){return e.versions.find((function(e){return e.isLast}))};function u(e,t){var n,a,o=function(e,t){var n=l(e);return[].concat(e.versions.filter((function(e){return e!==n})),[n]).find((function(e){return!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})}))}(e,t),i=null==o?void 0:o.docs.find((function(e){return!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})}));return{activeVersion:o,activeDoc:i,alternateDocVersions:i?(n=i.id,a={},e.versions.forEach((function(e){e.docs.forEach((function(t){t.id===n&&(a[e.name]=t)}))})),a):{}}}var s={},c=function(){var e;return null!=(e=i("docusaurus-plugin-content-docs"))?e:s},d=function(e){return function(e,t,n){void 0===t&&(t=o.m),void 0===n&&(n={});var r=i(e),a=null==r?void 0:r[t];if(!a&&n.failfast)throw new Error('Docusaurus plugin global data not found for "'+e+'" plugin with id "'+t+'".');return a}("docusaurus-plugin-content-docs",e,{failfast:!0})};function f(e){return void 0===e&&(e={}),function(e,t,n){void 0===n&&(n={});var a=Object.entries(e).sort((function(e,t){return t[1].path.localeCompare(e[1].path)})).find((function(e){var n=e[1];return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&n.failfast)throw new Error("Can't find active docs plugin for \""+t+'" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: '+Object.values(e).map((function(e){return e.path})).join(", "));return o}(c(),(0,r.TH)().pathname,e)}function p(e){return d(e).versions}function m(e){var t=d(e);return l(t)}function g(e){return u(d(e),(0,r.TH)().pathname)}function h(e){return function(e,t){var n=l(e);return{latestDocSuggestion:u(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(d(e),(0,r.TH)().pathname)}},4367:function(e,t,n){"use strict";n.r(t);var r={onRouteDidUpdate:function(e){var t=e.location,n=e.previousLocation;!n||t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash||(window.ga("set","page",t.pathname+t.search+t.hash),window.ga("send","pageview"))}};t.default=r},8320:function(e,t,n){"use strict";n.r(t);var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});var o={onRouteUpdate:function(e){var t=e.location,n=e.previousLocation;if(n&&t.pathname!==n.pathname){var r=window.setTimeout((function(){a().start()}),200);return function(){return window.clearTimeout(r)}}},onRouteDidUpdate:function(){a().done()}};t.default=o},3310:function(e,t,n){"use strict";n.r(t);var r,a,o=n(7410),i=n(6809);r=o.Z,a=i.default.themeConfig.prism.additionalLanguages,globalThis.Prism=r,a.forEach((function(e){n(7748)("./prism-"+e)})),delete globalThis.Prism},9471:function(e,t,n){"use strict";n.d(t,{Z:function(){return o}});var r=n(7294),a="iconExternalLink_nPIU";function o(e){var t=e.width,n=void 0===t?13.5:t,o=e.height,i=void 0===o?13.5:o;return r.createElement("svg",{width:n,height:i,"aria-hidden":"true",viewBox:"0 0 24 24",className:a},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"}))}},3285:function(e,t,n){"use strict";n.d(t,{Z:function(){return Pt}});var r=n(7294),a=n(4334),o=n(4763),i=n(1944),l=n(3117),u=n(6550),s=n(5999),c=n(5936),d="docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){var e=(0,r.useRef)(null),t=(0,u.k6)().action,n=(0,r.useCallback)((function(e){e.preventDefault();var t,n=null!=(t=document.querySelector("main:first-of-type"))?t:document.getElementById(d);n&&f(n)}),[]);return(0,c.S)((function(n){var r=n.location;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}var m=(0,s.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 g(e){var t,n=null!=(t=e.children)?t:m,a=p(),o=a.containerRef,i=a.onClick;return r.createElement("div",{ref:o,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:"#"+d,onClick:i}),n))}var h=n(5281),v=n(9727),b="skipToContent_fXgn";function y(){return r.createElement(g,{className:b})}var w=n(6668),E=n(9689),k=n(102),x=["width","height","color","strokeWidth","className"];function S(e){var t=e.width,n=void 0===t?21:t,a=e.height,o=void 0===a?21:a,i=e.color,u=void 0===i?"currentColor":i,s=e.strokeWidth,c=void 0===s?1.2:s,d=(e.className,(0,k.Z)(e,x));return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:n,height:o},d),r.createElement("g",{stroke:u,strokeWidth:c},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}var T="closeButton_CVFx";function _(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,s.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",T,e.className)}),r.createElement(S,{width:14,height:14,strokeWidth:3.1}))}var C="content_knG7";function A(e){var t=(0,w.L)().announcementBar.content;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(C,e.className),dangerouslySetInnerHTML:{__html:t}}))}var P="announcementBar_mb4j",O="announcementBarPlaceholder_vyr4",N="announcementBarClose_gvF7",I="announcementBarContent_xLdY";function R(){var e=(0,w.L)().announcementBar,t=(0,E.nT)(),n=t.isActive,a=t.close;if(!n)return null;var o=e.backgroundColor,i=e.textColor,l=e.isCloseable;return r.createElement("div",{className:P,style:{backgroundColor:o,color:i},role:"banner"},l&&r.createElement("div",{className:O}),r.createElement(A,{className:I}),l&&r.createElement(_,{onClick:a,className:N}))}var L=n(2961),D=n(2466);var M=n(4700),z=n(3102),F=r.createContext(null);function B(e){var t,n,a,o,i,l,u,s=e.children,c=(t=(0,L.e)(),n=(0,z.HY)(),a=(0,r.useState)(!1),o=a[0],i=a[1],l=null!==n.component,u=(0,M.D9)(l),(0,r.useEffect)((function(){l&&!u&&i(!0)}),[l,u]),(0,r.useEffect)((function(){l?t.shown||i(!0):i(!1)}),[t.shown,l]),(0,r.useMemo)((function(){return[o,i]}),[o]));return r.createElement(F.Provider,{value:c},s)}function j(e){if(e.component){var t=e.component;return r.createElement(t,e.props)}}function U(){var e=(0,r.useContext)(F);if(!e)throw new M.i6("NavbarSecondaryMenuDisplayProvider");var t=e[0],n=e[1],a=(0,r.useCallback)((function(){return n(!1)}),[n]),o=(0,z.HY)();return(0,r.useMemo)((function(){return{shown:t,hide:a,content:j(o)}}),[a,o,t])}function Z(e){var t=e.header,n=e.primaryMenu,o=e.secondaryMenu,i=U().shown;return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},o)))}var $=n(2949),H=n(2389);function V(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function W(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}var G={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function q(e){var t=e.className,n=e.value,o=e.onChange,i=(0,H.Z)(),l=(0,s.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,s.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,s.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)(G.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",G.toggleButton,!i&&G.toggleButtonDisabled),type:"button",onClick:function(){return o("dark"===n?"light":"dark")},disabled:!i,title:l,"aria-label":l,"aria-live":"polite"},r.createElement(V,{className:(0,a.Z)(G.toggleIcon,G.lightToggleIcon)}),r.createElement(W,{className:(0,a.Z)(G.toggleIcon,G.darkToggleIcon)})))}var Y=r.memo(q);function K(e){var t=e.className,n=(0,w.L)().colorMode.disableSwitch,a=(0,$.I)(),o=a.colorMode,i=a.setColorMode;return n?null:r.createElement(Y,{className:t,value:o,onChange:i})}var Q=n(1327);function X(){return r.createElement(Q.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function J(){var e=(0,L.e)();return r.createElement("button",{type:"button","aria-label":(0,s.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:function(){return e.toggle()}},r.createElement(S,{color:"var(--ifm-color-emphasis-600)"}))}function ee(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(X,null),r.createElement(K,{className:"margin-right--md"}),r.createElement(J,null))}var te=n(9960),ne=n(4996),re=n(3919);function ae(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var oe=n(9471),ie=["activeBasePath","activeBaseRegex","to","href","label","html","isDropdownLink","prependBaseUrlToHref"];function le(e){var t=e.activeBasePath,n=e.activeBaseRegex,a=e.to,o=e.href,i=e.label,u=e.html,s=e.isDropdownLink,c=e.prependBaseUrlToHref,d=(0,k.Z)(e,ie),f=(0,ne.Z)(a),p=(0,ne.Z)(t),m=(0,ne.Z)(o,{forcePrependBaseUrl:!0}),g=i&&o&&!(0,re.Z)(o),h=u?{dangerouslySetInnerHTML:{__html:u}}:{children:r.createElement(r.Fragment,null,i,g&&r.createElement(oe.Z,s&&{width:12,height:12}))};return o?r.createElement(te.Z,(0,l.Z)({href:c?m:o},d,h)):r.createElement(te.Z,(0,l.Z)({to:f,isNavLink:!0},(t||n)&&{isActive:function(e,t){return n?ae(n,t.pathname):t.pathname.startsWith(p)}},d,h))}var ue=["className","isDropdownItem"],se=["className","isDropdownItem"],ce=["mobile","position"];function de(e){var t=e.className,n=e.isDropdownItem,o=void 0!==n&&n,i=(0,k.Z)(e,ue),u=r.createElement(le,(0,l.Z)({className:(0,a.Z)(o?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:o},i));return o?r.createElement("li",null,u):u}function fe(e){var t=e.className,n=(e.isDropdownItem,(0,k.Z)(e,se));return r.createElement("li",{className:"menu__list-item"},r.createElement(le,(0,l.Z)({className:(0,a.Z)("menu__link",t)},n)))}function pe(e){var t,n=e.mobile,a=void 0!==n&&n,o=(e.position,(0,k.Z)(e,ce)),i=a?fe:de;return r.createElement(i,(0,l.Z)({},o,{activeClassName:null!=(t=o.activeClassName)?t:a?"menu__link--active":"navbar__link--active"}))}var me=n(6043),ge=n(8596),he=n(2263);var ve=["items","position","className","onClick"],be=["items","className","position","onClick"],ye=["mobile"];function we(e,t){return e.some((function(e){return function(e,t){return!!(0,ge.Mg)(e.to,t)||!!ae(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)}))}function Ee(e){var t,n=e.items,o=e.position,i=e.className,u=(e.onClick,(0,k.Z)(e,ve)),s=(0,r.useRef)(null),c=(0,r.useState)(!1),d=c[0],f=c[1];return(0,r.useEffect)((function(){var e=function(e){s.current&&!s.current.contains(e.target)&&f(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),function(){document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[s]),r.createElement("div",{ref:s,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===o,"dropdown--show":d})},r.createElement(le,(0,l.Z)({"aria-haspopup":"true","aria-expanded":d,role:"button",href:u.to?void 0:"#",className:(0,a.Z)("navbar__link",i)},u,{onClick:u.to?void 0:function(e){return e.preventDefault()},onKeyDown:function(e){"Enter"===e.key&&(e.preventDefault(),f(!d))}}),null!=(t=u.children)?t:u.label),r.createElement("ul",{className:"dropdown__menu"},n.map((function(e,t){return r.createElement(Ze,(0,l.Z)({isDropdownItem:!0,onKeyDown:function(e){if(t===n.length-1&&"Tab"===e.key){e.preventDefault(),f(!1);var r=s.current.nextElementSibling;if(r)(r instanceof HTMLAnchorElement?r:r.querySelector("a")).focus()}},activeClassName:"dropdown__link--active"},e,{key:t}))}))))}function ke(e){var t,n,o=e.items,i=e.className,s=(e.position,e.onClick),c=(0,k.Z)(e,be),d=(n=(0,he.Z)().siteConfig.baseUrl,(0,u.TH)().pathname.replace(n,"/")),f=we(o,d),p=(0,me.u)({initialState:function(){return!f}}),m=p.collapsed,g=p.toggleCollapsed,h=p.setCollapsed;return(0,r.useEffect)((function(){f&&h(!f)}),[d,f,h]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":m})},r.createElement(le,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",i)},c,{onClick:function(e){e.preventDefault(),g()}}),null!=(t=c.children)?t:c.label),r.createElement(me.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:m},o.map((function(e,t){return r.createElement(Ze,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:s,activeClassName:"menu__link--active"},e,{key:t}))}))))}function xe(e){var t=e.mobile,n=void 0!==t&&t,a=(0,k.Z)(e,ye),o=n?ke:Ee;return r.createElement(o,a)}var Se=n(4711),Te=["width","height"];function _e(e){var t=e.width,n=void 0===t?20:t,a=e.height,o=void 0===a?20:a,i=(0,k.Z)(e,Te);return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:n,height:o,"aria-hidden":!0},i),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"}))}var Ce="iconLanguage_nlXk",Ae=["mobile","dropdownItemsBefore","dropdownItemsAfter"];var Pe=n(1875),Oe="searchBox_ZlJk";function Ne(e){var t=e.children,n=e.className;return r.createElement("div",{className:(0,a.Z)(n,Oe)},t)}var Ie=n(143),Re=n(3651),Le=["docId","label","docsPluginId"];var De=["sidebarId","label","docsPluginId"];var Me=["label","to","docsPluginId"];var ze=n(373),Fe=["mobile","docsPluginId","dropdownActiveClassDisabled","dropdownItemsBefore","dropdownItemsAfter"],Be=function(e){return e.docs.find((function(t){return t.id===e.mainDocId}))};var je={default:pe,localeDropdown:function(e){var t=e.mobile,n=e.dropdownItemsBefore,a=e.dropdownItemsAfter,o=(0,k.Z)(e,Ae),i=(0,he.Z)().i18n,c=i.currentLocale,d=i.locales,f=i.localeConfigs,p=(0,Se.l)(),m=(0,u.TH)(),g=m.search,h=m.hash,v=d.map((function(e){var n=""+("pathname://"+p.createUrl({locale:e,fullyQualified:!1}))+g+h;return{label:f[e].label,lang:f[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===c?t?"menu__link--active":"dropdown__link--active":""}})),b=[].concat(n,v,a),y=t?(0,s.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):f[c].label;return r.createElement(xe,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(_e,{className:Ce}),y),items:b}))},search:function(e){var t=e.mobile,n=e.className;return t?null:r.createElement(Ne,{className:n},r.createElement(Pe.Z,null))},dropdown:xe,html:function(e){var t=e.value,n=e.className,o=e.mobile,i=void 0!==o&&o,l=e.isDropdownItem,u=void 0!==l&&l,s=u?"li":"div";return r.createElement(s,{className:(0,a.Z)({navbar__item:!i&&!u,"menu__list-item":i},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){var t=e.docId,n=e.label,a=e.docsPluginId,o=(0,k.Z)(e,Le),i=(0,Ie.Iw)(a).activeDoc,u=(0,Re.vY)(t,a);return null===u?null:r.createElement(pe,(0,l.Z)({exact:!0},o,{isActive:function(){return(null==i?void 0:i.path)===u.path||!(null==i||!i.sidebar)&&i.sidebar===u.sidebar},label:null!=n?n:u.id,to:u.path}))},docSidebar:function(e){var t=e.sidebarId,n=e.label,a=e.docsPluginId,o=(0,k.Z)(e,De),i=(0,Ie.Iw)(a).activeDoc,u=(0,Re.oz)(t,a).link;if(!u)throw new Error('DocSidebarNavbarItem: Sidebar with ID "'+t+"\" doesn't have anything to be linked to.");return r.createElement(pe,(0,l.Z)({exact:!0},o,{isActive:function(){return(null==i?void 0:i.sidebar)===t},label:null!=n?n:u.label,to:u.path}))},docsVersion:function(e){var t=e.label,n=e.to,a=e.docsPluginId,o=(0,k.Z)(e,Me),i=(0,Re.lO)(a)[0],u=null!=t?t:i.label,s=null!=n?n:function(e){return e.docs.find((function(t){return t.id===e.mainDocId}))}(i).path;return r.createElement(pe,(0,l.Z)({},o,{label:u,to:s}))},docsVersionDropdown:function(e){var t=e.mobile,n=e.docsPluginId,a=e.dropdownActiveClassDisabled,o=e.dropdownItemsBefore,i=e.dropdownItemsAfter,c=(0,k.Z)(e,Fe),d=(0,u.TH)(),f=d.search,p=d.hash,m=(0,Ie.Iw)(n),g=(0,Ie.gB)(n),h=(0,ze.J)(n).savePreferredVersionName,v=g.map((function(e){var t,n=null!=(t=m.alternateDocVersions[e.name])?t:Be(e);return{label:e.label,to:""+n.path+f+p,isActive:function(){return e===m.activeVersion},onClick:function(){return h(e.name)}}})),b=[].concat(o,v,i),y=(0,Re.lO)(n)[0],w=t&&b.length>1?(0,s.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):y.label,E=t&&b.length>1?void 0:Be(y).path;return b.length<=1?r.createElement(pe,(0,l.Z)({},c,{mobile:t,label:w,to:E,isActive:a?function(){return!1}:void 0})):r.createElement(xe,(0,l.Z)({},c,{mobile:t,label:w,to:E,items:b,isActive:a?function(){return!1}:void 0}))}},Ue=["type"];function Ze(e){var t=e.type,n=(0,k.Z)(e,Ue),a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=je[a];if(!o)throw new Error('No NavbarItem component found for type "'+t+'".');return r.createElement(o,n)}function $e(){var e=(0,L.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map((function(t,n){return r.createElement(Ze,(0,l.Z)({mobile:!0},t,{onClick:function(){return e.toggle()},key:n}))})))}function He(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(s.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 Ve(){var e=0===(0,w.L)().navbar.items.length,t=U();return r.createElement(r.Fragment,null,!e&&r.createElement(He,{onClick:function(){return t.hide()}}),t.content)}function We(){var e,t=(0,L.e)();return void 0===(e=t.shown)&&(e=!0),(0,r.useEffect)((function(){return document.body.style.overflow=e?"hidden":"visible",function(){document.body.style.overflow="visible"}}),[e]),t.shouldRender?r.createElement(Z,{header:r.createElement(ee,null),primaryMenu:r.createElement($e,null),secondaryMenu:r.createElement(Ve,null)}):null}var Ge="navbarHideable_m1mJ",qe="navbarHidden_jGov";function Ye(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Ke(e){var t=e.children,n=(0,w.L)().navbar,o=n.hideOnScroll,i=n.style,l=(0,L.e)(),u=function(e){var t=(0,r.useState)(e),n=t[0],a=t[1],o=(0,r.useRef)(!1),i=(0,r.useRef)(0),l=(0,r.useCallback)((function(e){null!==e&&(i.current=e.getBoundingClientRect().height)}),[]);return(0,D.RF)((function(t,n){var r=t.scrollY;if(e)if(r=l?a(!1):r+s0&&r.createElement(pt,{links:n}),logo:a&&r.createElement(vt,{logo:a}),copyright:t&&r.createElement(bt,{copyright:t})})}var Et=r.memo(wt),kt=n(12),xt="docusaurus.tab.",St=r.createContext(void 0);var Tt=(0,M.Qc)([$.S,E.pl,function(e){var t=e.children,n=function(){var e=(0,r.useState)({}),t=e[0],n=e[1],a=(0,r.useCallback)((function(e,t){(0,kt.W)("docusaurus.tab."+e).set(t)}),[]);(0,r.useEffect)((function(){try{var e={};(0,kt._)().forEach((function(t){if(t.startsWith(xt)){var n=t.substring(xt.length);e[n]=(0,kt.W)(t).get()}})),n(e)}catch(t){console.error(t)}}),[]);var o=(0,r.useCallback)((function(e,t){n((function(n){var r;return Object.assign({},n,((r={})[e]=t,r))})),a(e,t)}),[a]);return(0,r.useMemo)((function(){return{tabGroupChoices:t,setTabGroupChoices:o}}),[t,o])}();return r.createElement(St.Provider,{value:n},t)},D.OC,ze.L5,i.VC,function(e){var t=e.children;return r.createElement(z.n2,null,r.createElement(L.M,null,r.createElement(B,null,t)))}]);function _t(e){var t=e.children;return r.createElement(Tt,null,t)}function Ct(e){var t=e.error,n=e.tryAgain;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(s.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(s.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}var At="mainWrapper_z2l0";function Pt(e){var t=e.children,n=e.noFooter,l=e.wrapperClassName,u=e.title,s=e.description;return(0,v.t)(),r.createElement(_t,null,r.createElement(i.d,{title:u,description:s}),r.createElement(y,null),r.createElement(R,null),r.createElement(at,null),r.createElement("div",{id:d,className:(0,a.Z)(h.k.wrapper.main,At,l)},r.createElement(o.Z,{fallback:function(e){return r.createElement(Ct,e)}},t)),!n&&r.createElement(Et,null))}},1327:function(e,t,n){"use strict";n.d(t,{Z:function(){return p}});var r=n(3117),a=n(102),o=n(7294),i=n(9960),l=n(4996),u=n(2263),s=n(6668),c=n(941),d=["imageClassName","titleClassName"];function f(e){var t=e.logo,n=e.alt,r=e.imageClassName,a={light:(0,l.Z)(t.src),dark:(0,l.Z)(t.srcDark||t.src)},i=o.createElement(c.Z,{className:t.className,sources:a,height:t.height,width:t.width,alt:n,style:t.style});return r?o.createElement("div",{className:r},i):i}function p(e){var t,n=(0,u.Z)().siteConfig.title,c=(0,s.L)().navbar,p=c.title,m=c.logo,g=e.imageClassName,h=e.titleClassName,v=(0,a.Z)(e,d),b=(0,l.Z)((null==m?void 0:m.href)||"/"),y=p?"":n,w=null!=(t=null==m?void 0:m.alt)?t:y;return o.createElement(i.Z,(0,r.Z)({to:b},v,(null==m?void 0:m.target)&&{target:m.target}),m&&o.createElement(f,{logo:m,alt:w,imageClassName:g}),null!=p&&o.createElement("b",{className:h},p))}},197:function(e,t,n){"use strict";n.d(t,{Z:function(){return o}});var r=n(7294),a=n(5742);function o(e){var t=e.locale,n=e.version,o=e.tag,i=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),o&&r.createElement("meta",{name:"docusaurus_tag",content:o}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),o&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},941:function(e,t,n){"use strict";n.d(t,{Z:function(){return d}});var r=n(3117),a=n(102),o=n(7294),i=n(4334),l=n(2389),u=n(2949),s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"},c=["sources","className","alt"];function d(e){var t=(0,l.Z)(),n=(0,u.I)().colorMode,d=e.sources,f=e.className,p=e.alt,m=(0,a.Z)(e,c),g=t?"dark"===n?["dark"]:["light"]:["light","dark"];return o.createElement(o.Fragment,null,g.map((function(e){return o.createElement("img",(0,r.Z)({key:e,src:d[e],alt:p,className:(0,i.Z)(s.themedImage,s["themedImage--"+e],f)},m))})))}},6043:function(e,t,n){"use strict";n.d(t,{u:function(){return s},z:function(){return v}});var r=n(3117),a=n(102),o=n(7294),i=n(412),l=["collapsed"],u=["lazy"];function s(e){var t=e.initialState,n=(0,o.useState)(null!=t&&t),r=n[0],a=n[1],i=(0,o.useCallback)((function(){a((function(e){return!e}))}),[]);return{collapsed:r,setCollapsed:a,toggleCollapsed:i}}var c={display:"none",overflow:"hidden",height:"0px"},d={display:"block",overflow:"visible",height:"auto"};function f(e,t){var n=t?c:d;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p(e){var t=e.collapsibleRef,n=e.collapsed,r=e.animation,a=(0,o.useRef)(!1);(0,o.useEffect)((function(){var e,o=t.current;function i(){var e,t,n=o.scrollHeight,a=null!=(e=null==r?void 0:r.duration)?e:function(e){var t=e/36;return Math.round(10*(4+15*Math.pow(t,.25)+t/5))}(n);return{transition:"height "+a+"ms "+(null!=(t=null==r?void 0:r.easing)?t:"ease-in-out"),height:n+"px"}}function l(){var e=i();o.style.transition=e.transition,o.style.height=e.height}if(!a.current)return f(o,n),void(a.current=!0);return o.style.willChange="height",e=requestAnimationFrame((function(){n?(l(),requestAnimationFrame((function(){o.style.height=c.height,o.style.overflow=c.overflow}))):(o.style.display="block",requestAnimationFrame((function(){l()})))})),function(){return cancelAnimationFrame(e)}}),[t,n,r])}function m(e){if(!i.Z.canUseDOM)return e?c:d}function g(e){var t=e.as,n=void 0===t?"div":t,r=e.collapsed,a=e.children,i=e.animation,l=e.onCollapseTransitionEnd,u=e.className,s=e.disableSSRStyle,c=(0,o.useRef)(null);return p({collapsibleRef:c,collapsed:r,animation:i}),o.createElement(n,{ref:c,style:s?void 0:m(r),onTransitionEnd:function(e){"height"===e.propertyName&&(f(c.current,r),null==l||l(r))},className:u},a)}function h(e){var t=e.collapsed,n=(0,a.Z)(e,l),i=(0,o.useState)(!t),u=i[0],s=i[1],c=(0,o.useState)(t),d=c[0],f=c[1];return(0,o.useLayoutEffect)((function(){t||s(!0)}),[t]),(0,o.useLayoutEffect)((function(){u&&f(t)}),[u,t]),u?o.createElement(g,(0,r.Z)({},n,{collapsed:d})):null}function v(e){var t=e.lazy,n=(0,a.Z)(e,u),r=t?h:g;return o.createElement(r,n)}},9689:function(e,t,n){"use strict";n.d(t,{nT:function(){return m},pl:function(){return p}});var r=n(7294),a=n(2389),o=n(12),i=n(4700),l=n(6668),u=(0,o.W)("docusaurus.announcement.dismiss"),s=(0,o.W)("docusaurus.announcement.id"),c=function(){return"true"===u.get()},d=function(e){return u.set(String(e))},f=r.createContext(null);function p(e){var t=e.children,n=function(){var e=(0,l.L)().announcementBar,t=(0,a.Z)(),n=(0,r.useState)((function(){return!!t&&c()})),o=n[0],i=n[1];(0,r.useEffect)((function(){i(c())}),[]);var u=(0,r.useCallback)((function(){d(!0),i(!0)}),[]);return(0,r.useEffect)((function(){if(e){var t=e.id,n=s.get();"annoucement-bar"===n&&(n="announcement-bar");var r=t!==n;s.set(t),r&&d(!1),!r&&c()||i(!1)}}),[e]),(0,r.useMemo)((function(){return{isActive:!!e&&!o,close:u}}),[e,o,u])}();return r.createElement(f.Provider,{value:n},t)}function m(){var e=(0,r.useContext)(f);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:function(e,t,n){"use strict";n.d(t,{I:function(){return h},S:function(){return g}});var r=n(7294),a=n(412),o=n(4700),i=n(12),l=n(6668),u=r.createContext(void 0),s="theme",c=(0,i.W)(s),d="light",f="dark",p=function(e){return e===f?f:d};function m(){var e=(0,l.L)().colorMode,t=e.defaultMode,n=e.disableSwitch,o=e.respectPrefersColorScheme,i=(0,r.useState)(function(e){return a.Z.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e)}(t)),u=i[0],m=i[1];(0,r.useEffect)((function(){n&&c.del()}),[n]);var g=(0,r.useCallback)((function(e,n){void 0===n&&(n={});var r=n.persist,a=void 0===r||r;e?(m(e),a&&function(e){c.set(p(e))}(e)):(m(o?window.matchMedia("(prefers-color-scheme: dark)").matches?f:d:t),c.del())}),[o,t]);(0,r.useEffect)((function(){document.documentElement.setAttribute("data-theme",p(u))}),[u]),(0,r.useEffect)((function(){if(!n){var e=function(e){if(e.key===s){var t=c.get();null!==t&&g(p(t))}};return window.addEventListener("storage",e),function(){return window.removeEventListener("storage",e)}}}),[n,g]);var h=(0,r.useRef)(!1);return(0,r.useEffect)((function(){if(!n||o){var e=window.matchMedia("(prefers-color-scheme: dark)"),t=function(){window.matchMedia("print").matches||h.current?h.current=window.matchMedia("print").matches:g(null)};return e.addListener(t),function(){return e.removeListener(t)}}}),[g,n,o]),(0,r.useMemo)((function(){return{colorMode:u,setColorMode:g,get isDarkTheme(){return u===f},setLightTheme:function(){g(d)},setDarkTheme:function(){g(f)}}}),[u,g])}function g(e){var t=e.children,n=m();return r.createElement(u.Provider,{value:n},t)}function h(){var e=(0,r.useContext)(u);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:function(e,t,n){"use strict";n.d(t,{J:function(){return y},L5:function(){return v}});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(3651),u=n(4700),s=n(12),c=function(e){return"docs-preferred-version-"+e},d=function(e,t,n){(0,s.W)(c(e),{persistence:t}).set(n)},f=function(e,t){return(0,s.W)(c(e),{persistence:t}).get()},p=function(e,t){(0,s.W)(c(e),{persistence:t}).del()};var m=r.createContext(null);function g(){var e=(0,a._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((function(){return Object.keys(e)}),[e]),o=(0,r.useState)((function(){return function(e){return Object.fromEntries(e.map((function(e){return[e,{preferredVersionName:null}]})))}(n)})),l=o[0],u=o[1];return(0,r.useEffect)((function(){u(function(e){var t=e.pluginIds,n=e.versionPersistence,r=e.allDocsData;return Object.fromEntries(t.map((function(e){return[e,(t=e,a=f(t,n),r[t].versions.some((function(e){return e.name===a}))?{preferredVersionName:a}:(p(t,n),{preferredVersionName:null}))];var t,a})))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]),[l,(0,r.useMemo)((function(){return{savePreferredVersion:function(e,n){d(e,t,n),u((function(t){var r;return Object.assign({},t,((r={})[e]={preferredVersionName:n},r))}))}}}),[t])]}function h(e){var t=e.children,n=g();return r.createElement(m.Provider,{value:n},t)}function v(e){var t=e.children;return l.cE?r.createElement(h,null,t):r.createElement(r.Fragment,null,t)}function b(){var e=(0,r.useContext)(m);if(!e)throw new u.i6("DocsPreferredVersionContextProvider");return e}function y(e){var t;void 0===e&&(e=o.m);var n=(0,a.zh)(e),i=b(),l=i[0],u=i[1],s=l[e].preferredVersionName;return{preferredVersion:null!=(t=n.versions.find((function(e){return e.name===s})))?t:null,savePreferredVersionName:(0,r.useCallback)((function(t){u.savePreferredVersion(e,t)}),[u,e])}}},1116:function(e,t,n){"use strict";n.d(t,{V:function(){return u},b:function(){return l}});var r=n(7294),a=n(4700),o=Symbol("EmptyContext"),i=r.createContext(o);function l(e){var t=e.children,n=e.name,a=e.items,o=(0,r.useMemo)((function(){return n&&a?{name:n,items:a}:null}),[n,a]);return r.createElement(i.Provider,{value:o},t)}function u(){var e=(0,r.useContext)(i);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},2961:function(e,t,n){"use strict";n.d(t,{M:function(){return f},e:function(){return p}});var r=n(7294),a=n(3102),o=n(7524),i=n(6550),l=n(4700);function u(e){!function(e){var t=(0,i.k6)(),n=(0,l.zX)(e);(0,r.useEffect)((function(){return t.block((function(e,t){return n(e,t)}))}),[t,n])}((function(t,n){if("POP"===n)return e(t,n)}))}var s=n(6668),c=r.createContext(void 0);function d(){var e,t=(e=(0,a.HY)(),0===(0,s.L)().navbar.items.length&&!e.component),n=(0,o.i)(),i=!t&&"mobile"===n,l=(0,r.useState)(!1),c=l[0],d=l[1];u((function(){if(c)return d(!1),!1}));var f=(0,r.useCallback)((function(){d((function(e){return!e}))}),[]);return(0,r.useEffect)((function(){"desktop"===n&&d(!1)}),[n]),(0,r.useMemo)((function(){return{disabled:t,shouldRender:i,toggle:f,shown:c}}),[t,i,f,c])}function f(e){var t=e.children,n=d();return r.createElement(c.Provider,{value:n},t)}function p(){var e=r.useContext(c);if(void 0===e)throw new l.i6("NavbarMobileSidebarProvider");return e}},3102:function(e,t,n){"use strict";n.d(t,{HY:function(){return l},Zo:function(){return u},n2:function(){return i}});var r=n(7294),a=n(4700),o=r.createContext(null);function i(e){var t=e.children,n=(0,r.useState)({component:null,props:null});return r.createElement(o.Provider,{value:n},t)}function l(){var e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function u(e){var t=e.component,n=e.props,i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");var l=i[1],u=(0,a.Ql)(n);return(0,r.useEffect)((function(){l({component:t,props:u})}),[l,t,u]),(0,r.useEffect)((function(){return function(){return l({component:null,props:null})}}),[l]),null}},9727:function(e,t,n){"use strict";n.d(t,{h:function(){return a},t:function(){return o}});var r=n(7294),a="navigation-with-keyboard";function o(){(0,r.useEffect)((function(){function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),function(){document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:function(e,t,n){"use strict";n.d(t,{i:function(){return s}});var r=n(7294),a=n(412),o="desktop",i="mobile",l="ssr";function u(){return a.Z.canUseDOM?window.innerWidth>996?o:i:l}function s(){var e=(0,r.useState)((function(){return u()})),t=e[0],n=e[1];return(0,r.useEffect)((function(){function e(){n(u())}return window.addEventListener("resize",e),function(){window.removeEventListener("resize",e),clearTimeout(undefined)}}),[]),t}},5281:function(e,t,n){"use strict";n.d(t,{k:function(){return r}});var 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:function(e){return"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:function(e){return"theme-doc-sidebar-item-category-level-"+e},docSidebarItemLinkLevel:function(e){return"theme-doc-sidebar-item-link-level-"+e}},blog:{}}},3651:function(e,t,n){"use strict";function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[a++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}n.d(t,{Wl:function(){return m},_F:function(){return h},cE:function(){return p},hI:function(){return k},lO:function(){return y},vY:function(){return E},oz:function(){return w},s1:function(){return b}});var o=n(7294),i=n(6550),l=n(8790),u=n(143),s=n(373),c=n(1116);function d(e){return Array.from(new Set(e))}var f=n(8596),p=!!u._r;function m(e){if(e.href)return e.href;for(var t,n=a(e.items);!(t=n()).done;){var r=t.value;if("link"===r.type)return r.href;if("category"===r.type){var o=m(r);if(o)return o}}}var g=function(e,t){return void 0!==e&&(0,f.Mg)(e,t)};function h(e,t){return"link"===e.type?g(e.href,t):"category"===e.type&&(g(e.href,t)||function(e,t){return e.some((function(e){return h(e,t)}))}(e.items,t))}function v(e){var t=e.sidebarItems,n=e.pathname,r=e.onlyCategories,o=void 0!==r&&r,i=[];return function e(t){for(var r,l=a(t);!(r=l()).done;){var u=r.value;if("category"===u.type&&((0,f.Mg)(u.href,n)||e(u.items))||"link"===u.type&&(0,f.Mg)(u.href,n))return o&&"category"!==u.type||i.unshift(u),!0}return!1}(t),i}function b(){var e,t=(0,c.V)(),n=(0,i.TH)().pathname;return!1!==(null==(e=(0,u.gA)())?void 0:e.pluginData.breadcrumbs)&&t?v({sidebarItems:t.items,pathname:n}):null}function y(e){var t=(0,u.Iw)(e).activeVersion,n=(0,s.J)(e).preferredVersion,r=(0,u.yW)(e);return(0,o.useMemo)((function(){return d([t,n,r].filter(Boolean))}),[t,n,r])}function w(e,t){var n=y(t);return(0,o.useMemo)((function(){var t=n.flatMap((function(e){return e.sidebars?Object.entries(e.sidebars):[]})),r=t.find((function(t){return t[0]===e}));if(!r)throw new Error("Can't find any sidebar with id \""+e+'" in version'+(n.length>1?"s":"")+" "+n.map((function(e){return e.name})).join(", ")+'".\n Available sidebar ids are:\n - '+Object.keys(t).join("\n- "));return r[1]}),[e,n])}function E(e,t){var n=y(t);return(0,o.useMemo)((function(){var t=n.flatMap((function(e){return e.docs})),r=t.find((function(t){return t.id===e}));if(!r){if(n.flatMap((function(e){return 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((function(e){return e.name})).join(", ")+'".\nAvailable doc ids are:\n- '+d(t.map((function(e){return e.id}))).join("\n- "))}return r}),[e,n])}function k(e){var t=e.route,n=e.versionMetadata,r=(0,i.TH)(),a=t.routes,o=a.find((function(e){return(0,i.LX)(r.pathname,e)}));if(!o)return null;var u=o.sidebar,s=u?n.docsSidebars[u]:void 0;return{docElement:(0,l.H)(a),sidebarName:u,sidebarItems:s}}},1944:function(e,t,n){"use strict";n.d(t,{FG:function(){return f},d:function(){return c},VC:function(){return p}});var r=n(7294),a=n(7459),o=n(5742),i=n(226);function l(){var e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var u=n(4996),s=n(2263);function c(e){var t=e.title,n=e.description,a=e.keywords,i=e.image,l=e.children,c=function(e){var t=(0,s.Z)().siteConfig,n=t.title,r=t.titleDelimiter;return null!=e&&e.trim().length?e.trim()+" "+r+" "+n:n}(t),d=(0,u.C)().withBaseUrl,f=i?d(i,{absolute:!0}):void 0;return r.createElement(o.Z,null,t&&r.createElement("title",null,c),t&&r.createElement("meta",{property:"og:title",content:c}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),f&&r.createElement("meta",{property:"og:image",content:f}),f&&r.createElement("meta",{name:"twitter:image",content:f}),l)}var d=r.createContext(void 0);function f(e){var t=e.className,n=e.children,i=r.useContext(d),l=(0,a.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(o.Z,null,r.createElement("html",{className:l})),n)}function p(e){var t=e.children,n=l(),o="plugin-"+n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,""),i="plugin-id-"+n.plugin.id;return r.createElement(f,{className:(0,a.Z)(o,i)},t)}},4700:function(e,t,n){"use strict";n.d(t,{i6:function(){return m},Qc:function(){return h},zX:function(){return f},D9:function(){return p},Ql:function(){return g}});var r=n(8900),a=n(1073);function o(e){return o=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},o(e)}var i=n(9817);function l(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}function u(e,t,n){return u=l()?Reflect.construct.bind():function(e,t,n){var r=[null];r.push.apply(r,t);var a=new(Function.bind.apply(e,r));return n&&(0,i.Z)(a,n.prototype),a},u.apply(null,arguments)}function s(e){var t="function"==typeof Map?new Map:void 0;return s=function(e){if(null===e||(n=e,-1===Function.toString.call(n).indexOf("[native code]")))return e;var n;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,r)}function r(){return u(e,arguments,o(this).constructor)}return r.prototype=Object.create(e.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),(0,i.Z)(r,e)},s(e)}var c=n(7294),d=n(412).Z.canUseDOM?c.useLayoutEffect:c.useEffect;function f(e){var t=(0,c.useRef)(e);return d((function(){t.current=e}),[e]),(0,c.useCallback)((function(){return t.current.apply(t,arguments)}),[])}function p(e){var t=(0,c.useRef)();return d((function(){t.current=e})),t.current}var m=function(e){function t(t,n){var a,o,i,l,u;return(u=e.call(this)||this).name="ReactContextError",u.message="Hook "+(null!=(a=null==(o=u.stack)||null==(i=o.split("\n")[1])||null==(l=i.match((0,r.Z)(/at (?:\w+\.)?(\w+)/,{name:1})))?void 0:l.groups.name)?a:"")+" is called outside the <"+t+">. "+(null!=n?n:""),u}return(0,a.Z)(t,e),t}(s(Error));function g(e){var t=Object.entries(e);return t.sort((function(e,t){return e[0].localeCompare(t[0])})),(0,c.useMemo)((function(){return e}),t.flat())}function h(e){return function(t){var n=t.children;return c.createElement(c.Fragment,null,e.reduceRight((function(e,t){return c.createElement(t,null,e)}),n))}}},8596:function(e,t,n){"use strict";n.d(t,{Mg:function(){return i},Ns:function(){return l}});var r=n(7294),a=n(723),o=n(2263);function i(e,t){var n=function(e){var t;return null==(t=!e||e.endsWith("/")?e:e+"/")?void 0:t.toLowerCase()};return n(e)===n(t)}function l(){var e=(0,o.Z)().siteConfig.baseUrl;return(0,r.useMemo)((function(){return function(e){var t=e.baseUrl;function n(e){return e.path===t&&!0===e.exact}function r(e){return e.path===t&&!e.exact}return function e(t){if(0!==t.length)return t.find(n)||e(t.filter(r).flatMap((function(e){var t;return null!=(t=e.routes)?t:[]})))}(e.routes)}({routes:a.Z,baseUrl:e})}),[e])}},2466:function(e,t,n){"use strict";n.d(t,{Ct:function(){return f},OC:function(){return u},RF:function(){return d}});var r=n(7294),a=n(412),o=n(2389),i=n(4700);var l=r.createContext(void 0);function u(e){var t,n=e.children,a=(t=(0,r.useRef)(!0),(0,r.useMemo)((function(){return{scrollEventsEnabledRef:t,enableScrollEvents:function(){t.current=!0},disableScrollEvents:function(){t.current=!1}}}),[]));return r.createElement(l.Provider,{value:a},n)}function s(){var e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}var c=function(){return a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null};function d(e,t){void 0===t&&(t=[]);var n=s().scrollEventsEnabledRef,a=(0,r.useRef)(c()),o=(0,i.zX)(e);(0,r.useEffect)((function(){var e=function(){if(n.current){var e=c();o(e,a.current),a.current=e}},t={passive:!0};return e(),window.addEventListener("scroll",e,t),function(){return window.removeEventListener("scroll",e,t)}}),[o,n].concat(t))}function f(){var e=(0,r.useRef)(null),t=(0,o.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:function(n){e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),function(){}}(n):function(e){var t=null,n=document.documentElement.scrollTop>e;return function r(){var a=document.documentElement.scrollTop;(n&&a>e||!n&&a=0;f--){var p=i[f];"."===p?o(i,f):".."===p?(o(i,f),d++):d&&(o(i,f),d--)}if(!s)for(;d--;d)i.unshift("..");!s||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m},l=n(2177);function u(e){return"/"===e.charAt(0)?e:"/"+e}function s(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function p(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=p(e,t,g(),w.location);c.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t
'};function a(e,t,n){return en?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),s=o.querySelector(r.barSelector),c=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),u(s,i(e,c,d)),1===e?(u(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){u(o,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),s=document.querySelector(r.parent);return u(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&p(a),s!=document.body&&c(s,"nprogress-custom-parent"),s.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),u=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function s(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=f(e),r=n+t;s(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);s(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:function(e){"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function a(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(a){return!1}}()?Object.assign:function(e,o){for(var i,l,u=a(e),s=1;s=d.reach);x+=k.value.length,k=k.next){var S=k.value;if(t.length>e.length)return;if(!(S instanceof a)){var T,_=1;if(b){if(!(T=o(E,x,e,v))||T.index>=e.length)break;var C=T.index,A=T.index+T[0].length,P=x;for(P+=k.value.length;C>=P;)P+=(k=k.next).value.length;if(x=P-=k.value.length,k.value instanceof a)continue;for(var O=k;O!==t.tail&&(Pd.reach&&(d.reach=L);var D=k.prev;if(I&&(D=u(t,D,I),x+=I.length),s(t,D,_),k=u(t,D,new a(f,h?r.tokenize(N,h):N,y,N)),R&&u(t,k,R),_>1){var M={cause:f+","+m,reach:L};i(e,t,n,k.prev,x,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function u(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function s(e,t,n){for(var r=t.next,a=0;a"+o.content+""},r}(),r=n;n.default=n,r.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]},r.languages.markup.tag.inside["attr-value"].inside.entity=r.languages.markup.entity,r.languages.markup.doctype.inside["internal-subset"].inside=r.languages.markup,r.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(r.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:r.languages[t]},n.cdata=/^$/i;var a={"included-cdata":{pattern://i,inside:n}};a["language-"+t]={pattern:/[\s\S]+/,inside:r.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:a},r.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(r.languages.markup.tag,"addAttribute",{value:function(e,t){r.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:r.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),r.languages.html=r.languages.markup,r.languages.mathml=r.languages.markup,r.languages.svg=r.languages.markup,r.languages.xml=r.languages.extend("markup",{}),r.languages.ssml=r.languages.xml,r.languages.atom=r.languages.xml,r.languages.rss=r.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},r.languages.c=r.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|[?:~]|[-+*/%&|^!=<>]=?/}),r.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),r.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},r.languages.c.string],char:r.languages.c.char,comment:r.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:r.languages.c}}}}),r.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 r.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"])}(r),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"))}(r),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(r),r.languages.javascript=r.languages.extend("clike",{"class-name":[r.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}|\?\?=?|\?\.?|[~:]/}),r.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,r.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:r.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:r.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:r.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:r.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:r.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),r.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:r.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"}}),r.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),r.languages.markup&&(r.languages.markup.tag.addInlined("script","javascript"),r.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")),r.languages.js=r.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}(r),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \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"(?:"+a+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(o),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(r),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,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\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:'"'},u=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(r),r.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:r.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+/},r.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 l=f(/^\{$/,/^\}$/);if(-1===l)continue;for(var u=n;u=0&&p(s,"variable-input")}}}}function c(e){return t[n+e]}function d(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,a=r.inside["interpolation-punctuation"],o=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function u(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function s(t){var n={};n["interpolation-punctuation"]=a;var o=e.tokenize(t,n);if(3===o.length){var i=[1,1];i.push.apply(i,u(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,i)}return new e.Token("interpolation",o,r.alias,t)}function c(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,c={},d=u(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(i++,r)););return c[n]=a,n})).join(""),n,r),f=Object.keys(c);return i=0,function e(t){for(var n=0;n=f.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=f[i],o="string"==typeof r?r:r.content,l=o.indexOf(a);if(-1!==l){++i;var u=o.substring(0,l),d=s(c[a]),p=o.substring(l+a.length),m=[];if(u&&m.push(u),m.push(d),p){var g=[p];e(g),m.push.apply(m,g)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var h=r.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return"string"==typeof e?e:Array.isArray(e)?e.map(f).join(""):f(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=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}(r),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 o(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return a})),RegExp(e,t)}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:+(?:[\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:o(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},l=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===i(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:i(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var u=i(a);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(u=i(t[r-1])+u,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",u,null,u)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(r),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(r),r.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},r.languages.go=r.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/}),r.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete r.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var u=0;u=o.length);u++){var s=l[u];if("string"==typeof s||s.content&&"string"==typeof s.content){var c=o[a],d=n.tokenStack[c],f="string"==typeof s?s:s.content,p=t(r,c),m=f.indexOf(p);if(m>-1){++a;var g=f.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),v=f.substring(m+p.length),b=[];g&&b.push.apply(b,i([g])),b.push(h),v&&b.push.apply(b,i([v])),"string"==typeof s?l.splice.apply(l,[u,1].concat(b)):s.content=b}}else s.content&&i(s.content)}return l}(n.tokens)}}}})}(r),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}(r),r.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"}},r.languages.webmanifest=r.languages.json,r.languages.less=r.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:/[+\-*\/]/}),r.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),r.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:/[:;(){}]/},r.languages.objectivec=r.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 r.languages.objectivec["class-name"],r.languages.objc=r.languages.objectivec,r.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/},r.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:/[{}[\];(),.:]/},r.languages.python["string-interpolation"].inside.interpolation.inside.rest=r.languages.python,r.languages.py=r.languages.python,r.languages.reason=r.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/}),r.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 r.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}})}(r),r.languages.scss=r.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]+\}/}}}),r.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}]}),r.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),r.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}}),r.languages.scss.atrule.inside.rest=r.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:/[{}()\[\];:.]/}}(r),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}(r),r.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:/[()]/},t.Z=r},2503:function(){!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}}),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)},7345:function(){!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},2886:function(){Prism.languages.scala=Prism.languages.extend("java",{"triple-quoted-string":{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string"},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},keyword:/<-|=>|\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\b/,number:/\b0x(?:[\da-f]*\.)?[\da-f]+|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e\d+)?[dfl]?/i,builtin:/\b(?:Any|AnyRef|AnyVal|Boolean|Byte|Char|Double|Float|Int|Long|Nothing|Short|String|Unit)\b/,symbol:/'[^\d\s\\]\w*/}),Prism.languages.insertBefore("scala","triple-quoted-string",{"string-interpolation":{pattern:/\b[a-z]\w*(?:"""(?:[^$]|\$(?:[^{]|\{(?:[^{}]|\{[^{}]*\})*\}))*?"""|"(?:[^$"\r\n]|\$(?:[^{]|\{(?:[^{}]|\{[^{}]*\})*\}))*")/i,greedy:!0,inside:{id:{pattern:/^\w+/,greedy:!0,alias:"function"},escape:{pattern:/\\\$"|\$[$"]/,greedy:!0,alias:"symbol"},interpolation:{pattern:/\$(?:\w+|\{(?:[^{}]|\{[^{}]*\})*\})/,greedy:!0,inside:{punctuation:/^\$\{?|\}$/,expression:{pattern:/[\s\S]+/,inside:Prism.languages.scala}}},string:/[\s\S]+/}}}),delete Prism.languages.scala["class-name"],delete Prism.languages.scala.function},7748:function(e,t,n){var r={"./prism-java":2503,"./prism-protobuf":7345,"./prism-scala":2886};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=7748},2703:function(e,t,n){"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:function(e,t,n){e.exports=n(2703)()},414:function(e){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:function(e,t,n){"use strict";var r=n(7294),a=n(7418),o=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n