1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([["21684"],{71329(e,n,i){i.r(n),i.d(n,{metadata:()=>s,default:()=>p,frontMatter:()=>o,contentTitle:()=>h,toc:()=>l,assets:()=>c});var s=JSON.parse('{"id":"guides/graphql-server-specification","title":"GraphQL Server Specification","description":"Relay GraphQL server specification guide","source":"@site/versioned_docs/version-v21.0.1/guides/graphql-server-specification.mdx","sourceDirName":"guides","slug":"/guides/graphql-server-specification/","permalink":"/docs/guides/graphql-server-specification/","draft":false,"unlisted":false,"editUrl":"https://github.com/facebook/relay/tree/main/website/versioned_docs/version-v21.0.1/guides/graphql-server-specification.mdx","tags":[],"version":"v21.0.1","frontMatter":{"id":"graphql-server-specification","title":"GraphQL Server Specification","slug":"/guides/graphql-server-specification/","description":"Relay GraphQL server specification guide","keywords":["GraphQL","server","specification"]},"sidebar":"docs","previous":{"title":"Client Schema Extensions","permalink":"/docs/guides/client-schema-extensions/"},"next":{"title":"Persisted Queries","permalink":"/docs/guides/persisted-queries/"}}'),t=i(74848),a=i(28453),r=i(86898);let o={id:"graphql-server-specification",title:"GraphQL Server Specification",slug:"/guides/graphql-server-specification/",description:"Relay GraphQL server specification guide",keywords:["GraphQL","server","specification"]},h,c={},l=[{value:"Preface",id:"preface",level:2},{value:"Schema",id:"schema",level:2},{value:"Object Identification",id:"object-identification",level:2},{value:"Connections",id:"connections",level:2},{value:"GraphQL Conf Talk",id:"graphql-conf-talk",level:2},{value:"Further Reading",id:"further-reading",level:2}];function d(e){let n={a:"a",code:"code",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.p,{children:"The goal of this document is to specify the assumptions that Relay makes about a GraphQL server and demonstrate them through an example GraphQL schema."}),"\n",(0,t.jsx)(n.p,{children:"Table of Contents:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#preface",children:"Preface"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#schema",children:"Schema"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#object-identification",children:"Object Identification"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#connections",children:"Connections"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#further-reading",children:"Further Reading"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"preface",children:"Preface"}),"\n",(0,t.jsx)(n.p,{children:"The two core assumptions that Relay makes about a GraphQL server are that it provides:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsx)(n.li,{children:"A mechanism for refetching an object."}),"\n",(0,t.jsx)(n.li,{children:"A description of how to page through connections."}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This example demonstrates all two of these assumptions. This example is not comprehensive, but it is designed to quickly introduce these core assumptions, to provide some context before diving into the more detailed specification of the library."}),"\n",(0,t.jsx)(n.p,{children:"The premise of the example is that we want to use GraphQL to query for information about ships and factions in the original Star Wars trilogy."}),"\n",(0,t.jsxs)(n.p,{children:["It is assumed that the reader is already familiar with ",(0,t.jsx)(n.a,{href:"http://graphql.org/",children:"GraphQL"}),"; if not, the README for ",(0,t.jsx)(n.a,{href:"https://github.com/graphql/graphql-js",children:"GraphQL.js"})," is a good place to start."]}),"\n",(0,t.jsxs)(n.p,{children:["It is also assumed that the reader is already familiar with ",(0,t.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Star_Wars",children:"Star Wars"}),"; if not, the 1977 version of Star Wars is a good place to start, though the 1997 Special Edition will serve for the purposes of this document."]}),"\n",(0,t.jsx)(n.h2,{id:"schema",children:"Schema"}),"\n",(0,t.jsx)(n.p,{children:"The schema described below will be used to demonstrate the functionality that a GraphQL server used by Relay should implement. The two core types are a faction and a ship in the Star Wars universe, where a faction has many ships associated with it."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:"interface Node {\n id: ID!\n}\n\ntype Faction implements Node {\n id: ID!\n name: String\n ships: ShipConnection\n}\n\ntype Ship implements Node {\n id: ID!\n name: String\n}\n\ntype ShipConnection {\n edges: [ShipEdge]\n pageInfo: PageInfo!\n}\n\ntype ShipEdge {\n cursor: String!\n node: Ship\n}\n\ntype PageInfo {\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n startCursor: String\n endCursor: String\n}\n\ntype Query {\n rebels: Faction\n empire: Faction\n node(id: ID!): Node\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"object-identification",children:"Object Identification"}),"\n",(0,t.jsxs)(n.p,{children:["Both ",(0,t.jsx)(n.code,{children:"Faction"})," and ",(0,t.jsx)(n.code,{children:"Ship"})," have identifiers that we can use to refetch them. We expose this capability to Relay through the ",(0,t.jsx)(n.code,{children:"Node"})," interface and the ",(0,t.jsx)(n.code,{children:"node"})," field on the root query type."]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"Node"})," interface contains a single field, ",(0,t.jsx)(n.code,{children:"id"}),", which is an ",(0,t.jsx)(n.code,{children:"ID!"}),". The ",(0,t.jsx)(n.code,{children:"node"})," root field takes a single argument, an ",(0,t.jsx)(n.code,{children:"ID!"}),", and returns a ",(0,t.jsx)(n.code,{children:"Node"}),". These two work in concert to allow refetching; if we pass the ",(0,t.jsx)(n.code,{children:"id"})," returned in that field to the ",(0,t.jsx)(n.code,{children:"node"})," field, we get the object back."]}),"\n",(0,t.jsx)(n.p,{children:"Let's see this in action, and query for the ID of the rebels:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:"query RebelsQuery {\n rebels {\n id\n name\n }\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"returns"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "rebels": {\
1n "id": "RmFjdGlvbjox",\n "name": "Alliance to Restore the Republic"\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"So now we know the ID of the Rebels in our system. We can now refetch them:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:'query RebelsRefetchQuery {\n node(id: "RmFjdGlvbjox") {\n id\n ... on Faction {\n name\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"returns"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "node": {\n "id": "RmFjdGlvbjox",\n "name": "Alliance to Restore the Republic"\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"If we do the same thing with the Empire, we'll find that it returns a different ID, and we can refetch it as well:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:"query EmpireQuery {\n empire {\n id\n name\n }\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"yields"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "empire": {\n "id": "RmFjdGlvbjoy",\n "name": "Galactic Empire"\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"and"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:'query EmpireRefetchQuery {\n node(id: "RmFjdGlvbjoy") {\n id\n ... on Faction {\n name\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"yields"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "node": {\n "id": "RmFjdGlvbjoy",\n "name": "Galactic Empire"\n }\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"Node"})," interface and ",(0,t.jsx)(n.code,{children:"node"})," field assume globally unique IDs for this refetching. A system without globally unique IDs can usually synthesize them by combining the type with the type-specific ID, which is what was done in this example."]}),"\n",(0,t.jsxs)(n.p,{children:["The IDs we got back were base64 strings. IDs are designed to be opaque (the only thing that should be passed to the ",(0,t.jsx)(n.code,{children:"id"})," argument on ",(0,t.jsx)(n.code,{children:"node"})," is the unaltered result of querying ",(0,t.jsx)(n.code,{children:"id"})," on some object in the system), and base64ing a string is a useful convention in GraphQL to remind viewers that the string is an opaque identifier."]}),"\n",(0,t.jsxs)(n.p,{children:["Complete details on how the server should behave are available in the ",(0,t.jsx)(n.a,{href:"https://graphql.org/learn/global-object-identification/",children:"GraphQL Object Identification"})," best practices guide in the GraphQL site."]}),"\n",(0,t.jsx)(n.h2,{id:"connections",children:"Connections"}),"\n",(0,t.jsx)(n.p,{children:"A faction has many ships in the Star Wars universe. Relay contains functionality to make manipulating one-to-many relationships easy, using a standardized way of expressing these one-to-many relationships. This standard connection model offers ways of slicing and paginating through the connection."}),"\n",(0,t.jsx)(n.p,{children:"Let's take the rebels, and ask for their first ship:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:"query RebelsShipsQuery {\n rebels {\n name\n ships(first: 1) {\n edges {\n node {\n name\n }\n }\n }\n }\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"yields"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "rebels": {\n "name": "Alliance to Restore the Republic",\n "ships": {\n "edges": [\n {\n "node": {\n "name": "X-Wing"\n }\n }\n ]\n }\n }\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["That used the ",(0,t.jsx)(n.code,{children:"first"})," argument to ",(0,t.jsx)(n.code,{children:"ships"})," to slice the result set down to the first one. But what if we wanted to paginate through it? On each edge, a cursor will be exposed that we can use to paginate. Let's ask for the first two this time, and get the cursor as well:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"query MoreRebelShipsQuery {\n rebels {\n name\n ships(first: 2) {\n edges {\n cursor\n node {\n name\n }\n }\n }\n }\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"and we get back"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'\n{\n "rebels": {\
1n "name": "Alliance to Restore the Republic",\n "ships": {\n "edges": [\n {\n "cursor": "YXJyYXljb25uZWN0aW9uOjA=",\n "node": {\n "name": "X-Wing"\n }\n },\n {\n "cursor": "YXJyYXljb25uZWN0aW9uOjE=",\n "node": {\n "name": "Y-Wing"\n }\n }\n ]\n }\n }\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["Notice that the cursor is a base64 string. That's the pattern from earlier: the server is reminding us that this is an opaque string. We can pass this string back to the server as the ",(0,t.jsx)(n.code,{children:"after"})," argument to the ",(0,t.jsx)(n.code,{children:"ships"})," field, which will let us ask for the next three ships after the last one in the previous result:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:'\nquery EndOfRebelShipsQuery {\n rebels {\n name\n ships(first: 3 after: "YXJyYXljb25uZWN0aW9uOjE=") {\n edges {\n cursor\n node {\n name\n }\n }\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"gives us"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'\n\n{\n "rebels": {\n "name": "Alliance to Restore the Republic",\n "ships": {\n "edges": [\n {\n "cursor": "YXJyYXljb25uZWN0aW9uOjI=",\n "node": {\n "name": "A-Wing"\n }\n },\n {\n "cursor": "YXJyYXljb25uZWN0aW9uOjM=",\n "node": {\n "name": "Millennium Falcon"\n }\n },\n {\n "cursor": "YXJyYXljb25uZWN0aW9uOjQ=",\n "node": {\n "name": "Home One"\n }\n }\n ]\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"Sweet! Let's keep going and get the next four!"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:'query RebelsQuery {\n rebels {\n name\n ships(first: 4 after: "YXJyYXljb25uZWN0aW9uOjQ=") {\n edges {\n cursor\n node {\n name\n }\n }\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"yields"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "rebels": {\n "name": "Alliance to Restore the Republic",\n "ships": {\n "edges": []\n }\n }\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["Hm. There were no more ships; guess there were only five in the system for the rebels. It would have been nice to know that we'd reached the end of the connection, without having to do another round trip in order to verify that. The connection model exposes this capability with a type called ",(0,t.jsx)(n.code,{children:"PageInfo"}),". So let's issue the two queries that got us ships again, but this time ask for ",(0,t.jsx)(n.code,{children:"hasNextPage"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-graphql",children:'query EndOfRebelShipsQuery {\n rebels {\n name\n originalShips: ships(first: 2) {\n edges {\n node {\n name\n }\n }\n pageInfo {\n hasNextPage\n }\n }\n moreShips: ships(first: 3 after: "YXJyYXljb25uZWN0aW9uOjE=") {\n edges {\n node {\n name\n }\n }\n pageInfo {\n hasNextPage\n }\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"and we get back"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "rebels": {\n "name": "Alliance to Restore the Republic",\n "originalShips": {\n "edges": [\n {\n "node": {\n "name": "X-Wing"\n }\n },\n {\n "node": {\n "name": "Y-Wing"\n }\n }\n ],\n "pageInfo": {\n "hasNextPage": true\n }\n },\n "moreShips": {\n "edges": [\n {\n "node": {\n "name": "A-Wing"\n }\n },\n {\n "node": {\n "name": "Millennium Falcon"\n }\n },\n {\n "node": {\n "name": "Home One"\n }\n }\n ],\n "pageInfo": {\n "hasNextPage": false\n }\n }\n }\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"So on the first query for ships, GraphQL told us there was a next page, but on the next one, it told us we'd reached the end of the connection."}),"\n",(0,t.jsx)(n.p,{children:"Relay uses all of this functionality to build out abstractions around connections, to make these easy to work with efficie
1ntly without having to manually manage cursors on the client."}),"\n",(0,t.jsxs)(n.p,{children:["Complete details on how the server should behave are available in the ",(0,t.jsx)(n.a,{href:"https://relay.dev/graphql/connections.htm",children:"GraphQL Cursor Connections"})," spec."]}),"\n",(0,t.jsx)(n.h2,{id:"graphql-conf-talk",children:"GraphQL Conf Talk"}),"\n",(0,t.jsx)(n.p,{children:"Sabrina Wasserman, an engineer at Meta, gave a talk at GraphQL Conf 2024 deriving the GraphQL connection spec, and explaining how having the behavior of list pagination specified can enable powerful tooling for clients broadly, not just Relay."}),"\n",(0,t.jsx)("iframe",{src:"https://www.youtube-nocookie.com/embed/PGBC-0E-kco",width:640,height:360,allowFullScreen:!0,frameBorder:"0"}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["This concludes the overview of the GraphQL Server Specifications. For the detailed requirements of a Relay-compliant GraphQL server, a more formal description of the ",(0,t.jsx)(n.a,{href:"https://relay.dev/graphql/connections.htm",children:"Relay cursor connection"})," model, the ",(0,t.jsx)(n.a,{href:"https://graphql.org/learn/global-object-identification/",children:"GraphQL global object identification"})," model are all available."]}),"\n",(0,t.jsxs)(n.p,{children:["To see code implementing the specification, the ",(0,t.jsx)(n.a,{href:"https://github.com/graphql/graphql-relay-js",children:"GraphQL.js Relay library"})," provides helper functions for creating nodes and connections; that repository's ",(0,t.jsx)(n.a,{href:"https://github.com/graphql/graphql-relay-js/tree/main/src/__tests__",children:(0,t.jsx)(n.code,{children:"__tests__"})})," folder contains an implementation of the above example as integration tests for the repository."]}),"\n",(0,t.jsx)(r.A,{})]})}function p(e={}){let{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},86898(e,n,i){i.d(n,{A:()=>g});var s=i(74848),t=i(95310),a=i(17352),r=i(96540);function o(){let e=window.encodeURI(JSON.stringify({title:"Feedback about "+window.location.pathname,description:"**!!! Required !!!**\n\nPlease modify the task description to let us know how the docs can be improved.\n\n**Please do not ask support questions via this form! Instead, ask in fburl.com/relay_support**",tag_ids:{add:[0xac96423e5b680,0x64079768ac750]}}));window.open("https://www.internalfb.com/tasks/?n="+e)}function h({children:e}){return(0,s.jsxs)("div",{className:"docsRating",id:"docsRating",children:[(0,s.jsx)("hr",{}),e]})}let c=()=>{let[e,n]=r.useState(!1),i=e=>{n(!0),window.ga&&window.ga("send",{hitType:"event",eventCategory:"button",eventAction:"feedback",eventValue:e})};return e?"Thank you for letting us know!":(0,s.jsxs)(s.Fragment,{children:["Is this page useful?",(0,s.jsx)("svg",{className:"i_thumbsup",alt:"Like",id:"docsRating-like",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 81.13 89.76",onClick:()=>i(1),children:(0,s.jsx)("path",{d:"M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z"})}),(0,s.jsx)("svg",{className:"i_thumbsdown",alt:"Dislike",id:"docsRating-dislike",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 81.13 89.76",onClick:()=>i(0),children:(0,s.jsx)("path",{d:"M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z"})})]})},l=()=>(0,s.jsxs)("p",{children:["Let us know how these docs can be improved by",(0,s.jsx)("a",{className:"button",role:"button",tabIndex:0,onClick:o,children:"Filing a task"})]}),d=()=>(0,s.jsxs)("p",{children:["Help us make the site even better by"," ",(0,s.jsx)(t.default,{to:"https://www.surveymonkey.com/r/FYC9TCJ",children:"answering a few quick questions"}),"."]}),p=()=>(0,s.jsxs)(h,{children:[(0,s.jsx)(l,{}),(0,s.jsx)(c,{}),(0,s.jsx)(d,{})]}),u=()=>(0,s.jsxs)(h,{children:[(0,s.jsx)(c,{}),(0,s.jsx)(d,{})]}),g=()=>(0,a.fbContent)({internal:(0,s.jsx)(p,{}),external:(0,s.jsx)(u,{})})},28453(e,n,i){i.d(n,{R:()=>r,x:()=>o});var s=i(96540);let t={},a=s.createContext(t);function r(e){let n=s.useContext(a);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.