pejay-ui 1.2.2 → 1.3.1
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/README.md +17 -2
- package/package.json +2 -2
- package/registry.json +33 -1
- package/templates/notes/create-pejay.md +222 -0
- package/templates/notes/notes-v1.md +516 -0
- package/templates/notes/notes-v2.md +764 -0
- package/templates/notes/notes-v3.md +574 -0
- package/templates/notes/notes-v4.md +811 -0
- package/templates/notes/notes-v5.md +579 -0
- package/templates/notes/notes-vf+1.md +311 -0
- package/templates/notes/notes-vfinal.md +852 -0
- package/templates/scaffolds/axios/api/index.ts +40 -0
- package/templates/scaffolds/axios/api/one.api.ts +94 -0
- package/templates/scaffolds/axios/endpoints.ts +9 -0
- package/templates/scaffolds/axios/index.ts +26 -0
- package/templates/scaffolds/axios/interceptors.ts +103 -0
- package/templates/scaffolds/axios/request.ts +32 -0
- package/templates/scaffolds/react-router/hook/useRouterSearch.ts +8 -0
- package/templates/scaffolds/react-router/router/guards/private.route.tsx +1 -0
- package/templates/scaffolds/react-router/router/index.ts +26 -0
- package/templates/scaffolds/react-router/router/layouts/error.layout.tsx +1 -1
- package/templates/scaffolds/redux-store/middlewares.ts +0 -0
- package/templates/scaffolds/redux-store/reducers.ts +30 -0
- package/templates/scaffolds/redux-store/selector/one.selector.ts +43 -0
- package/templates/scaffolds/redux-store/selector/two.selector.ts +11 -0
- package/templates/scaffolds/redux-store/slices/one.slice.ts +202 -0
- package/templates/scaffolds/redux-store/slices/two.slice.ts +21 -0
- package/templates/scaffolds/redux-store/store.ts +38 -0
- package/templates/scaffolds/rtk-query/baseApi.ts +24 -0
- package/templates/scaffolds/rtk-query/baseQuery.ts +12 -0
- package/templates/scaffolds/rtk-query/endpoints/api.one.ts +82 -0
- package/templates/scaffolds/rtk-query/endpoints/index.ts +1 -0
- package/templates/scaffolds/rtk-query/middlewares.ts +11 -0
- package/templates/scaffolds/rtk-query/queryTags.ts +13 -0
- package/templates/scaffolds/tanstack-query/api-base.ts +68 -68
- package/templates/scaffolds/tanstack-query/api-queries.ts +0 -19
- package/templates/scaffolds/tanstack-query/client.ts +8 -0
- package/templates/scaffolds/tanstack-query/module/index.ts +12 -12
- package/templates/scaffolds/tanstack-query/module/keys.ts +17 -17
- package/templates/scaffolds/tanstack-query/module/mappers.ts +15 -15
- package/templates/scaffolds/tanstack-query/module/mutations.ts +59 -55
- package/templates/scaffolds/tanstack-query/module/queries.ts +145 -156
- package/templates/scaffolds/tanstack-query/module/services.ts +74 -66
- package/templates/scaffolds/tanstack-router/layout/404.layout.tsx +3 -0
- package/templates/scaffolds/tanstack-router/layout/app.layout.tsx +10 -0
- package/templates/scaffolds/tanstack-router/layout/auth.layout.tsx +10 -0
- package/templates/scaffolds/tanstack-router/layout/error.layout.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/auth/login.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/one/index.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/one/one-id.tsx +128 -0
- package/templates/scaffolds/tanstack-router/router.ts +90 -0
- package/templates/scaffolds/tanstack-router/routes/_404.tsx +0 -0
- package/templates/scaffolds/tanstack-router/routes/__root.tsx +9 -0
- package/templates/scaffolds/tanstack-router/routes/_app.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/_auth.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/_error.tsx +0 -0
- package/templates/scaffolds/tanstack-router/routes/auth/login.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/one/$id.tsx +191 -0
- package/templates/scaffolds/tanstack-router/routes/one/index.tsx +6 -0
- package/templates/scripts/setup.bat +284 -0
- package/templates/scripts/setup.ps1 +318 -0
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
# TanStack Router + TanStack Query Integration
|
|
2
|
+
|
|
3
|
+
This document covers:
|
|
4
|
+
|
|
5
|
+
```txt
|
|
6
|
+
Loader
|
|
7
|
+
ensureQueryData()
|
|
8
|
+
useSuspenseQuery()
|
|
9
|
+
pendingComponent
|
|
10
|
+
Complete Route Lifecycle
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
These concepts are the foundation of most production TanStack Router applications.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Why Use Loaders With TanStack Query?
|
|
18
|
+
|
|
19
|
+
Without a loader:
|
|
20
|
+
|
|
21
|
+
```txt
|
|
22
|
+
Navigate
|
|
23
|
+
↓
|
|
24
|
+
Component Mounts
|
|
25
|
+
↓
|
|
26
|
+
useSuspenseQuery()
|
|
27
|
+
↓
|
|
28
|
+
Request Starts
|
|
29
|
+
↓
|
|
30
|
+
Data Arrives
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The request only starts after the component renders.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
With a loader:
|
|
38
|
+
|
|
39
|
+
```txt
|
|
40
|
+
Navigate
|
|
41
|
+
↓
|
|
42
|
+
Loader Runs First
|
|
43
|
+
↓
|
|
44
|
+
Query Starts
|
|
45
|
+
↓
|
|
46
|
+
Data Cached
|
|
47
|
+
↓
|
|
48
|
+
Component Mounts
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The route prepares data before rendering.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
# ensureQueryData()
|
|
56
|
+
|
|
57
|
+
The most common loader pattern.
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
export const Route = createFileRoute(
|
|
63
|
+
"/_app/users/$id"
|
|
64
|
+
)({
|
|
65
|
+
loader: ({ context, params }) =>
|
|
66
|
+
context.queryClient.ensureQueryData(
|
|
67
|
+
apiQueries.users.detail(params.id)
|
|
68
|
+
),
|
|
69
|
+
|
|
70
|
+
component: UserDetails,
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## What Does It Do?
|
|
77
|
+
|
|
78
|
+
Think:
|
|
79
|
+
|
|
80
|
+
```txt
|
|
81
|
+
If Data Exists In Cache
|
|
82
|
+
↓
|
|
83
|
+
Return Cached Data
|
|
84
|
+
|
|
85
|
+
Else
|
|
86
|
+
↓
|
|
87
|
+
Fetch Data
|
|
88
|
+
↓
|
|
89
|
+
Save To Cache
|
|
90
|
+
↓
|
|
91
|
+
Return Data
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Benefits
|
|
97
|
+
|
|
98
|
+
```txt
|
|
99
|
+
✓ Uses Query Cache
|
|
100
|
+
|
|
101
|
+
✓ Avoids Duplicate Requests
|
|
102
|
+
|
|
103
|
+
✓ Faster Navigation
|
|
104
|
+
|
|
105
|
+
✓ Works With Suspense
|
|
106
|
+
|
|
107
|
+
✓ Integrates Naturally With Mutations
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
# Complete Example
|
|
113
|
+
|
|
114
|
+
Query Factory:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
export const userQueries = {
|
|
118
|
+
detail: (id: string) =>
|
|
119
|
+
queryOptions({
|
|
120
|
+
queryKey: ["user", id],
|
|
121
|
+
|
|
122
|
+
queryFn: () =>
|
|
123
|
+
UserService.getById(id),
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
Route:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
export const Route = createFileRoute(
|
|
134
|
+
"/_app/users/$id"
|
|
135
|
+
)({
|
|
136
|
+
loader: ({ context, params }) =>
|
|
137
|
+
context.queryClient.ensureQueryData(
|
|
138
|
+
userQueries.detail(params.id)
|
|
139
|
+
),
|
|
140
|
+
|
|
141
|
+
component: UserDetails,
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
Component:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
export default function UserDetails() {
|
|
151
|
+
const { id } =
|
|
152
|
+
Route.useParams();
|
|
153
|
+
|
|
154
|
+
const { data } =
|
|
155
|
+
useSuspenseQuery(
|
|
156
|
+
userQueries.detail(id)
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div>
|
|
161
|
+
{data.name}
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
# Important Question
|
|
170
|
+
|
|
171
|
+
Why call:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
useSuspenseQuery(
|
|
175
|
+
userQueries.detail(id)
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
again inside the component?
|
|
180
|
+
|
|
181
|
+
Didn't the loader already fetch the data?
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
Answer:
|
|
186
|
+
|
|
187
|
+
```txt
|
|
188
|
+
Loader
|
|
189
|
+
↓
|
|
190
|
+
Puts Data Into Cache
|
|
191
|
+
|
|
192
|
+
Component
|
|
193
|
+
↓
|
|
194
|
+
Reads Data From Cache
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
No second request occurs.
|
|
198
|
+
|
|
199
|
+
The component is simply reading cached data.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
# Request Lifecycle
|
|
204
|
+
|
|
205
|
+
First Visit:
|
|
206
|
+
|
|
207
|
+
```txt
|
|
208
|
+
Navigate
|
|
209
|
+
↓
|
|
210
|
+
Loader Runs
|
|
211
|
+
↓
|
|
212
|
+
ensureQueryData()
|
|
213
|
+
↓
|
|
214
|
+
API Request
|
|
215
|
+
↓
|
|
216
|
+
Query Cache Updated
|
|
217
|
+
↓
|
|
218
|
+
Component Mounts
|
|
219
|
+
↓
|
|
220
|
+
useSuspenseQuery()
|
|
221
|
+
↓
|
|
222
|
+
Reads Cache
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
Second Visit:
|
|
228
|
+
|
|
229
|
+
```txt
|
|
230
|
+
Navigate
|
|
231
|
+
↓
|
|
232
|
+
Loader Runs
|
|
233
|
+
↓
|
|
234
|
+
Cache Already Exists
|
|
235
|
+
↓
|
|
236
|
+
No Request
|
|
237
|
+
↓
|
|
238
|
+
Component Mounts
|
|
239
|
+
↓
|
|
240
|
+
useSuspenseQuery()
|
|
241
|
+
↓
|
|
242
|
+
Reads Cache
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
# pendingComponent
|
|
248
|
+
|
|
249
|
+
Provides route-level loading UI.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
export const Route = createFileRoute(
|
|
255
|
+
"/_app/users/$id"
|
|
256
|
+
)({
|
|
257
|
+
pendingComponent:
|
|
258
|
+
UserSkeleton,
|
|
259
|
+
|
|
260
|
+
loader: ({ context, params }) =>
|
|
261
|
+
context.queryClient.ensureQueryData(
|
|
262
|
+
userQueries.detail(params.id)
|
|
263
|
+
),
|
|
264
|
+
|
|
265
|
+
component: UserDetails,
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
# What Happens?
|
|
272
|
+
|
|
273
|
+
```txt
|
|
274
|
+
Navigate
|
|
275
|
+
↓
|
|
276
|
+
Loader Starts
|
|
277
|
+
↓
|
|
278
|
+
Data Not Ready
|
|
279
|
+
↓
|
|
280
|
+
pendingComponent Appears
|
|
281
|
+
↓
|
|
282
|
+
Data Arrives
|
|
283
|
+
↓
|
|
284
|
+
Real Component Renders
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
# Why Suspense Works So Well Here
|
|
290
|
+
|
|
291
|
+
Component:
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
const { data } =
|
|
295
|
+
useSuspenseQuery(
|
|
296
|
+
userQueries.detail(id)
|
|
297
|
+
);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Normally Suspense would wait for the query.
|
|
301
|
+
|
|
302
|
+
But:
|
|
303
|
+
|
|
304
|
+
```txt
|
|
305
|
+
Loader
|
|
306
|
+
↓
|
|
307
|
+
Already Loaded Query
|
|
308
|
+
↓
|
|
309
|
+
Cache Ready
|
|
310
|
+
↓
|
|
311
|
+
Suspense Instantly Resolves
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Meaning:
|
|
315
|
+
|
|
316
|
+
```txt
|
|
317
|
+
Less Loading
|
|
318
|
+
Less Flicker
|
|
319
|
+
Better UX
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
# useQuery vs useSuspenseQuery
|
|
325
|
+
|
|
326
|
+
## useQuery
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
const {
|
|
330
|
+
data,
|
|
331
|
+
isLoading,
|
|
332
|
+
error,
|
|
333
|
+
} = useQuery(
|
|
334
|
+
userQueries.detail(id)
|
|
335
|
+
);
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Requires handling:
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
if (isLoading) {
|
|
342
|
+
return <Loader />;
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## useSuspenseQuery
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
const { data } =
|
|
352
|
+
useSuspenseQuery(
|
|
353
|
+
userQueries.detail(id)
|
|
354
|
+
);
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
No:
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
isLoading
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
No:
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
if (loading)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
No:
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
if (data)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Suspense guarantees data exists.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
# Typical TanStack Router Setup
|
|
380
|
+
|
|
381
|
+
Route:
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
export const Route = createFileRoute(
|
|
385
|
+
"/_app/users/$id"
|
|
386
|
+
)({
|
|
387
|
+
pendingComponent:
|
|
388
|
+
UserSkeleton,
|
|
389
|
+
|
|
390
|
+
loader: ({ context, params }) =>
|
|
391
|
+
context.queryClient.ensureQueryData(
|
|
392
|
+
userQueries.detail(params.id)
|
|
393
|
+
),
|
|
394
|
+
|
|
395
|
+
component: UserDetails,
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
Component:
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
export default function UserDetails() {
|
|
405
|
+
const { id } =
|
|
406
|
+
Route.useParams();
|
|
407
|
+
|
|
408
|
+
const { data } =
|
|
409
|
+
useSuspenseQuery(
|
|
410
|
+
userQueries.detail(id)
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<div>{data.name}</div>
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
This is probably the most common enterprise TanStack Router pattern.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
# When To Use Route.useLoaderData()
|
|
424
|
+
|
|
425
|
+
Example:
|
|
426
|
+
|
|
427
|
+
```tsx
|
|
428
|
+
loader: async () => ({
|
|
429
|
+
pageTitle: "Users",
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Component:
|
|
434
|
+
|
|
435
|
+
```tsx
|
|
436
|
+
const data =
|
|
437
|
+
Route.useLoaderData();
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Good for:
|
|
441
|
+
|
|
442
|
+
```txt
|
|
443
|
+
Metadata
|
|
444
|
+
Configuration
|
|
445
|
+
Simple Route Information
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
# When To Use useSuspenseQuery()
|
|
451
|
+
|
|
452
|
+
Good for:
|
|
453
|
+
|
|
454
|
+
```txt
|
|
455
|
+
API Data
|
|
456
|
+
Server Data
|
|
457
|
+
CRUD Screens
|
|
458
|
+
Tables
|
|
459
|
+
Detail Pages
|
|
460
|
+
Dashboards
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
# Complete Mental Model
|
|
466
|
+
|
|
467
|
+
```txt
|
|
468
|
+
URL
|
|
469
|
+
↓
|
|
470
|
+
Route Match
|
|
471
|
+
↓
|
|
472
|
+
beforeLoad()
|
|
473
|
+
↓
|
|
474
|
+
loader()
|
|
475
|
+
↓
|
|
476
|
+
ensureQueryData()
|
|
477
|
+
↓
|
|
478
|
+
Query Cache Filled
|
|
479
|
+
↓
|
|
480
|
+
pendingComponent
|
|
481
|
+
↓
|
|
482
|
+
Component Mounts
|
|
483
|
+
↓
|
|
484
|
+
useSuspenseQuery()
|
|
485
|
+
↓
|
|
486
|
+
Reads Cached Data
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
# Recommended Pattern For CRM Apps
|
|
492
|
+
|
|
493
|
+
```tsx
|
|
494
|
+
beforeLoad()
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
for:
|
|
498
|
+
|
|
499
|
+
```txt
|
|
500
|
+
Auth
|
|
501
|
+
Permissions
|
|
502
|
+
Roles
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
```tsx
|
|
508
|
+
loader()
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
for:
|
|
512
|
+
|
|
513
|
+
```txt
|
|
514
|
+
Prefetching Queries
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
```tsx
|
|
520
|
+
ensureQueryData()
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
for:
|
|
524
|
+
|
|
525
|
+
```txt
|
|
526
|
+
Cache Population
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
```tsx
|
|
532
|
+
pendingComponent()
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
for:
|
|
536
|
+
|
|
537
|
+
```txt
|
|
538
|
+
Page Skeletons
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
```tsx
|
|
544
|
+
useSuspenseQuery()
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
for:
|
|
548
|
+
|
|
549
|
+
```txt
|
|
550
|
+
Reading Data
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
# Final Rule
|
|
556
|
+
|
|
557
|
+
If a page needs server data:
|
|
558
|
+
|
|
559
|
+
```txt
|
|
560
|
+
Route
|
|
561
|
+
↓
|
|
562
|
+
loader()
|
|
563
|
+
↓
|
|
564
|
+
ensureQueryData()
|
|
565
|
+
↓
|
|
566
|
+
useSuspenseQuery()
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
If a page only needs route information:
|
|
570
|
+
|
|
571
|
+
```txt
|
|
572
|
+
Route
|
|
573
|
+
↓
|
|
574
|
+
loader()
|
|
575
|
+
↓
|
|
576
|
+
Route.useLoaderData()
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
This distinction alone will help keep TanStack Router applications clean and predictable.
|