@apollo/client 4.2.0-alpha.2 → 4.2.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/__cjs/core/ApolloClient.cjs +9 -9
- package/__cjs/core/ApolloClient.cjs.map +1 -1
- package/__cjs/core/ApolloClient.d.cts +131 -21
- package/__cjs/link/ws/index.cjs +9 -1
- package/__cjs/link/ws/index.cjs.map +1 -1
- package/__cjs/link/ws/index.d.cts +1 -1
- package/__cjs/react/hooks/useBackgroundQuery.cjs.map +1 -1
- package/__cjs/react/hooks/useBackgroundQuery.d.cts +1466 -65
- package/__cjs/react/hooks/useLazyQuery.cjs.map +1 -1
- package/__cjs/react/hooks/useLazyQuery.d.cts +346 -39
- package/__cjs/react/hooks/useLoadableQuery.cjs.map +1 -1
- package/__cjs/react/hooks/useLoadableQuery.d.cts +492 -49
- package/__cjs/react/hooks/useMutation.cjs +5 -48
- package/__cjs/react/hooks/useMutation.cjs.map +1 -1
- package/__cjs/react/hooks/useMutation.d.cts +239 -130
- package/__cjs/react/hooks/useQuery.cjs.map +1 -1
- package/__cjs/react/hooks/useQuery.d.cts +570 -40
- package/__cjs/react/hooks/useSubscription.cjs +1 -1
- package/__cjs/react/hooks/useSubscription.cjs.map +1 -1
- package/__cjs/react/hooks/useSubscription.d.cts +2 -2
- package/__cjs/react/hooks/useSuspenseQuery.cjs.map +1 -1
- package/__cjs/react/hooks/useSuspenseQuery.d.cts +734 -45
- package/__cjs/version.cjs +1 -1
- package/core/ApolloClient.d.ts +131 -21
- package/core/ApolloClient.js +9 -9
- package/core/ApolloClient.js.map +1 -1
- package/link/ws/index.d.ts +1 -1
- package/link/ws/index.js +9 -1
- package/link/ws/index.js.map +1 -1
- package/package.json +3 -7
- package/react/hooks/useBackgroundQuery.d.ts +1466 -65
- package/react/hooks/useBackgroundQuery.js.map +1 -1
- package/react/hooks/useLazyQuery.d.ts +346 -39
- package/react/hooks/useLazyQuery.js.map +1 -1
- package/react/hooks/useLoadableQuery.d.ts +492 -49
- package/react/hooks/useLoadableQuery.js.map +1 -1
- package/react/hooks/useMutation.d.ts +239 -130
- package/react/hooks/useMutation.js +5 -48
- package/react/hooks/useMutation.js.map +1 -1
- package/react/hooks/useQuery.d.ts +570 -40
- package/react/hooks/useQuery.js.map +1 -1
- package/react/hooks/useSubscription.d.ts +2 -2
- package/react/hooks/useSubscription.js +1 -1
- package/react/hooks/useSubscription.js.map +1 -1
- package/react/hooks/useSuspenseQuery.d.ts +734 -45
- package/react/hooks/useSuspenseQuery.js.map +1 -1
- package/react/hooks-compiled/useBackgroundQuery.d.ts +1466 -65
- package/react/hooks-compiled/useBackgroundQuery.js.map +1 -1
- package/react/hooks-compiled/useLazyQuery.d.ts +346 -39
- package/react/hooks-compiled/useLazyQuery.js.map +1 -1
- package/react/hooks-compiled/useLoadableQuery.d.ts +492 -49
- package/react/hooks-compiled/useLoadableQuery.js.map +1 -1
- package/react/hooks-compiled/useMutation.d.ts +239 -130
- package/react/hooks-compiled/useMutation.js +4 -47
- package/react/hooks-compiled/useMutation.js.map +1 -1
- package/react/hooks-compiled/useQuery.d.ts +570 -40
- package/react/hooks-compiled/useQuery.js.map +1 -1
- package/react/hooks-compiled/useSubscription.d.ts +2 -2
- package/react/hooks-compiled/useSubscription.js +1 -1
- package/react/hooks-compiled/useSubscription.js.map +1 -1
- package/react/hooks-compiled/useSuspenseQuery.d.ts +734 -45
- package/react/hooks-compiled/useSuspenseQuery.js.map +1 -1
- package/skills/apollo-client/SKILL.md +168 -0
- package/skills/apollo-client/references/caching.md +560 -0
- package/skills/apollo-client/references/error-handling.md +350 -0
- package/skills/apollo-client/references/fragments.md +804 -0
- package/skills/apollo-client/references/integration-client.md +336 -0
- package/skills/apollo-client/references/integration-nextjs.md +325 -0
- package/skills/apollo-client/references/integration-react-router.md +256 -0
- package/skills/apollo-client/references/integration-tanstack-start.md +378 -0
- package/skills/apollo-client/references/mutations.md +549 -0
- package/skills/apollo-client/references/queries.md +416 -0
- package/skills/apollo-client/references/state-management.md +428 -0
- package/skills/apollo-client/references/suspense-hooks.md +773 -0
- package/skills/apollo-client/references/troubleshooting.md +487 -0
- package/skills/apollo-client/references/typescript-codegen.md +133 -0
- package/version.js +1 -1
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# State Management Reference
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Reactive Variables](#reactive-variables)
|
|
6
|
+
- [Local-Only Fields](#local-only-fields)
|
|
7
|
+
- [LocalState Resolvers](#localstate-resolvers)
|
|
8
|
+
- [Combining Remote and Local State](#combining-remote-and-local-state)
|
|
9
|
+
- [useReactiveVar Hook](#usereactivevar-hook)
|
|
10
|
+
|
|
11
|
+
## Reactive Variables
|
|
12
|
+
|
|
13
|
+
Reactive variables are a way to store local state outside of the Apollo Client cache while still triggering reactive updates.
|
|
14
|
+
|
|
15
|
+
**Important**: Reactive variables store a single value that notifies `ApolloClient` instances when changed. They do not have separate values per ApolloClient instance. In multi-user environments like SSR, global or module-level reactive variables could be shared between users and cause data leaks. In frameworks that use SSR, always avoid storing reactive variables as globals.
|
|
16
|
+
|
|
17
|
+
### Creating Reactive Variables
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { makeVar } from "@apollo/client";
|
|
21
|
+
|
|
22
|
+
// Simple reactive variable
|
|
23
|
+
export const isLoggedInVar = makeVar<boolean>(false);
|
|
24
|
+
|
|
25
|
+
// Object reactive variable
|
|
26
|
+
export const cartItemsVar = makeVar<CartItem[]>([]);
|
|
27
|
+
|
|
28
|
+
// Complex state
|
|
29
|
+
interface AppState {
|
|
30
|
+
theme: "light" | "dark";
|
|
31
|
+
sidebarOpen: boolean;
|
|
32
|
+
notifications: Notification[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const appStateVar = makeVar<AppState>({
|
|
36
|
+
theme: "light",
|
|
37
|
+
sidebarOpen: true,
|
|
38
|
+
notifications: [],
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Reading Reactive Variables
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
// Direct read (non-reactive)
|
|
46
|
+
const isLoggedIn = isLoggedInVar();
|
|
47
|
+
|
|
48
|
+
// Reactive read in component
|
|
49
|
+
import { useReactiveVar } from "@apollo/client/react";
|
|
50
|
+
|
|
51
|
+
function AuthButton() {
|
|
52
|
+
const isLoggedIn = useReactiveVar(isLoggedInVar);
|
|
53
|
+
|
|
54
|
+
return isLoggedIn ?
|
|
55
|
+
<button onClick={() => isLoggedInVar(false)}>Logout</button>
|
|
56
|
+
: <button onClick={() => isLoggedInVar(true)}>Login</button>;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Updating Reactive Variables
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Set new value
|
|
64
|
+
isLoggedInVar(true);
|
|
65
|
+
|
|
66
|
+
// Update based on current value
|
|
67
|
+
cartItemsVar([...cartItemsVar(), newItem]);
|
|
68
|
+
|
|
69
|
+
// Update object state
|
|
70
|
+
appStateVar({
|
|
71
|
+
...appStateVar(),
|
|
72
|
+
theme: "dark",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Helper function pattern
|
|
76
|
+
export function toggleSidebar() {
|
|
77
|
+
const current = appStateVar();
|
|
78
|
+
appStateVar({ ...current, sidebarOpen: !current.sidebarOpen });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function addNotification(notification: Notification) {
|
|
82
|
+
const current = appStateVar();
|
|
83
|
+
appStateVar({
|
|
84
|
+
...current,
|
|
85
|
+
notifications: [...current.notifications, notification],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Local-Only Fields
|
|
91
|
+
|
|
92
|
+
Local-only fields are fields defined in queries but resolved entirely on the client using the `@client` directive.
|
|
93
|
+
|
|
94
|
+
**Important**: To use any `@client` fields, you need to add `LocalState` to the `ApolloClient` initialization:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { ApolloClient, InMemoryCache } from "@apollo/client";
|
|
98
|
+
import { LocalState } from "@apollo/client/local-state";
|
|
99
|
+
|
|
100
|
+
const client = new ApolloClient({
|
|
101
|
+
cache: new InMemoryCache(),
|
|
102
|
+
localState: new LocalState({}),
|
|
103
|
+
// ... other options
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> **Note**: `LocalState` is an Apollo Client 4.x concept and did not exist as a class in previous versions. In previous versions, a `localState` option was not necessary, and local resolvers (if used) could be passed directly to the `ApolloClient` constructor.
|
|
108
|
+
|
|
109
|
+
### Basic @client Fields
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
const GET_USER_WITH_LOCAL = gql`
|
|
113
|
+
query GetUserWithLocal($id: ID!) {
|
|
114
|
+
user(id: $id) {
|
|
115
|
+
id
|
|
116
|
+
name
|
|
117
|
+
email
|
|
118
|
+
# Local-only fields
|
|
119
|
+
isSelected @client
|
|
120
|
+
displayName @client
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
function UserCard({ userId }: { userId: string }) {
|
|
126
|
+
const { data } = useQuery(GET_USER_WITH_LOCAL, {
|
|
127
|
+
variables: { id: userId },
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div className={data?.user.isSelected ? "selected" : ""}>
|
|
132
|
+
<h2>{data?.user.displayName}</h2>
|
|
133
|
+
<p>{data?.user.email}</p>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Local Field Read Functions (Type Policies)
|
|
140
|
+
|
|
141
|
+
Local field `read` functions are defined in entity-level type policies. You can use reactive variables inside these `read` functions, along with other calculations or derived values:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const cache = new InMemoryCache({
|
|
145
|
+
typePolicies: {
|
|
146
|
+
User: {
|
|
147
|
+
fields: {
|
|
148
|
+
// Simple local field from reactive variable
|
|
149
|
+
isSelected: {
|
|
150
|
+
read(_, { readField }) {
|
|
151
|
+
const id = readField("id");
|
|
152
|
+
return selectedUsersVar().includes(id);
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// Computed local field (derived value)
|
|
157
|
+
displayName: {
|
|
158
|
+
read(_, { readField }) {
|
|
159
|
+
const name = readField("name");
|
|
160
|
+
const email = readField("email");
|
|
161
|
+
return name || email?.split("@")[0] || "Anonymous";
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## LocalState Resolvers
|
|
171
|
+
|
|
172
|
+
### Query-Level Local Resolvers
|
|
173
|
+
|
|
174
|
+
Query-level local fields can be defined using `LocalState` resolvers. **Note**: Do not read reactive variables inside LocalState resolvers - this is not a documented/tested feature. It might not behave as expected.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { LocalState } from "@apollo/client/local-state";
|
|
178
|
+
|
|
179
|
+
const client = new ApolloClient({
|
|
180
|
+
cache: new InMemoryCache(),
|
|
181
|
+
localState: new LocalState({
|
|
182
|
+
resolvers: {
|
|
183
|
+
Query: {
|
|
184
|
+
// Read from localStorage
|
|
185
|
+
theme: () => {
|
|
186
|
+
if (typeof window !== "undefined") {
|
|
187
|
+
return localStorage.getItem("theme") || "light";
|
|
188
|
+
}
|
|
189
|
+
return "light";
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
// Read from cache
|
|
193
|
+
currentUser: (_, __, { cache }) => {
|
|
194
|
+
if (typeof window === "undefined") return null;
|
|
195
|
+
const userId = localStorage.getItem("currentUserId");
|
|
196
|
+
if (!userId) return null;
|
|
197
|
+
return cache.readFragment({
|
|
198
|
+
id: cache.identify({ __typename: "User", id: userId }),
|
|
199
|
+
fragment: gql`
|
|
200
|
+
fragment CurrentUser on User {
|
|
201
|
+
id
|
|
202
|
+
name
|
|
203
|
+
email
|
|
204
|
+
}
|
|
205
|
+
`,
|
|
206
|
+
});
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// Compute value
|
|
210
|
+
isOnline: () => {
|
|
211
|
+
if (typeof navigator !== "undefined") {
|
|
212
|
+
return navigator.onLine;
|
|
213
|
+
}
|
|
214
|
+
return true;
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
}),
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Using Local Query Fields
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
const GET_AUTH_STATE = gql`
|
|
226
|
+
query GetAuthState {
|
|
227
|
+
isLoggedIn @client
|
|
228
|
+
currentUser @client {
|
|
229
|
+
id
|
|
230
|
+
name
|
|
231
|
+
email
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
`;
|
|
235
|
+
|
|
236
|
+
function AuthStatus() {
|
|
237
|
+
const { data } = useQuery(GET_AUTH_STATE);
|
|
238
|
+
|
|
239
|
+
if (!data?.isLoggedIn) {
|
|
240
|
+
return <LoginButton />;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return <UserMenu user={data.currentUser} />;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Combining Remote and Local State
|
|
248
|
+
|
|
249
|
+
### Mixing Remote and Local Fields
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
const GET_PRODUCTS = gql`
|
|
253
|
+
query GetProducts {
|
|
254
|
+
products {
|
|
255
|
+
id
|
|
256
|
+
name
|
|
257
|
+
price
|
|
258
|
+
# Local fields
|
|
259
|
+
quantity @client
|
|
260
|
+
isInCart @client
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
`;
|
|
264
|
+
|
|
265
|
+
const cache = new InMemoryCache({
|
|
266
|
+
typePolicies: {
|
|
267
|
+
Product: {
|
|
268
|
+
fields: {
|
|
269
|
+
quantity: {
|
|
270
|
+
read(_, { readField }) {
|
|
271
|
+
const id = readField("id");
|
|
272
|
+
const cartItem = cartItemsVar().find(
|
|
273
|
+
(item) => item.productId === id
|
|
274
|
+
);
|
|
275
|
+
return cartItem?.quantity ?? 0;
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
isInCart: {
|
|
280
|
+
read(_, { readField }) {
|
|
281
|
+
const id = readField("id");
|
|
282
|
+
return cartItemsVar().some((item) => item.productId === id);
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Local Mutations
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
import { LocalState } from "@apollo/client/local-state";
|
|
295
|
+
|
|
296
|
+
const client = new ApolloClient({
|
|
297
|
+
cache: new InMemoryCache(),
|
|
298
|
+
localState: new LocalState({
|
|
299
|
+
resolvers: {
|
|
300
|
+
Mutation: {
|
|
301
|
+
addToCart: (_, { productId, quantity }, { cache }) => {
|
|
302
|
+
// Read current cart from cache
|
|
303
|
+
const { cart } = cache.readQuery({ query: GET_CART }) || { cart: [] };
|
|
304
|
+
|
|
305
|
+
const existing = cart.find((item) => item.productId === productId);
|
|
306
|
+
|
|
307
|
+
const updatedCart =
|
|
308
|
+
existing ?
|
|
309
|
+
cart.map((item) =>
|
|
310
|
+
item.productId === productId ?
|
|
311
|
+
{ ...item, quantity: item.quantity + quantity }
|
|
312
|
+
: item
|
|
313
|
+
)
|
|
314
|
+
: [...cart, { productId, quantity, __typename: "CartItem" }];
|
|
315
|
+
|
|
316
|
+
// Write updated cart back to cache
|
|
317
|
+
cache.writeQuery({
|
|
318
|
+
query: GET_CART,
|
|
319
|
+
data: { cart: updatedCart },
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return true;
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
}),
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const ADD_TO_CART = gql`
|
|
330
|
+
mutation AddToCart($productId: ID!, $quantity: Int!) {
|
|
331
|
+
addToCart(productId: $productId, quantity: $quantity) @client
|
|
332
|
+
}
|
|
333
|
+
`;
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Persisting Local State
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// Create a helper function to permanently subscribe to reactive variable changes, without creating memory leaks
|
|
340
|
+
function subscribeToVariable<T>(
|
|
341
|
+
weakRef: WeakRef<ReactiveVar<T>>,
|
|
342
|
+
listener: ReactiveListener<T>
|
|
343
|
+
) {
|
|
344
|
+
weakRef.deref()?.onNextChange((value) => {
|
|
345
|
+
listener(value);
|
|
346
|
+
subscribeToVariable(weakRef, listener);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Create reactive variable with persistence
|
|
351
|
+
const persistentCartVar = makeVar<CartItem[]>(
|
|
352
|
+
typeof window !== "undefined" && localStorage.getItem("cart") ?
|
|
353
|
+
JSON.parse(localStorage.getItem("cart")!)
|
|
354
|
+
: []
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
// Save to localStorage when reactive variable changes
|
|
358
|
+
subscribeToVariable(new WeakRef(persistentCartVar), (items) => {
|
|
359
|
+
try {
|
|
360
|
+
if (typeof window !== "undefined") {
|
|
361
|
+
localStorage.setItem("cart", JSON.stringify(items));
|
|
362
|
+
}
|
|
363
|
+
} catch (error) {
|
|
364
|
+
console.error("Failed to persist cart:", error);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## useReactiveVar Hook
|
|
370
|
+
|
|
371
|
+
The `useReactiveVar` hook subscribes a component to reactive variable updates.
|
|
372
|
+
|
|
373
|
+
### Basic Usage
|
|
374
|
+
|
|
375
|
+
```tsx
|
|
376
|
+
import { useReactiveVar } from "@apollo/client/react";
|
|
377
|
+
|
|
378
|
+
function ThemeToggle() {
|
|
379
|
+
const theme = useReactiveVar(themeVar);
|
|
380
|
+
|
|
381
|
+
return (
|
|
382
|
+
<button onClick={() => themeVar(theme === "light" ? "dark" : "light")}>
|
|
383
|
+
Current: {theme}
|
|
384
|
+
</button>
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### With Derived State
|
|
390
|
+
|
|
391
|
+
```tsx
|
|
392
|
+
function CartSummary() {
|
|
393
|
+
const cartItems = useReactiveVar(cartItemsVar);
|
|
394
|
+
|
|
395
|
+
// Derived values are computed on each render
|
|
396
|
+
const totalItems = cartItems.reduce((sum, item) => sum + item.quantity, 0);
|
|
397
|
+
const totalPrice = cartItems.reduce(
|
|
398
|
+
(sum, item) => sum + item.price * item.quantity,
|
|
399
|
+
0
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<div>
|
|
404
|
+
<p>Items: {totalItems}</p>
|
|
405
|
+
<p>Total: ${totalPrice.toFixed(2)}</p>
|
|
406
|
+
</div>
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Multiple Reactive Variables
|
|
412
|
+
|
|
413
|
+
```tsx
|
|
414
|
+
function AppLayout() {
|
|
415
|
+
const theme = useReactiveVar(themeVar);
|
|
416
|
+
const sidebarOpen = useReactiveVar(sidebarOpenVar);
|
|
417
|
+
const isLoggedIn = useReactiveVar(isLoggedInVar);
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<div className={`app ${theme}`}>
|
|
421
|
+
{isLoggedIn && sidebarOpen && <Sidebar />}
|
|
422
|
+
<main>
|
|
423
|
+
<Outlet />
|
|
424
|
+
</main>
|
|
425
|
+
</div>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
```
|