@solidjs/router 0.11.5 → 0.12.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 +2 -3
- package/dist/data/cache.d.ts +4 -5
- package/dist/data/cache.js +15 -16
- package/dist/data/createAsync.d.ts +15 -2
- package/dist/data/createAsync.js +30 -5
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.js +1 -1
- package/dist/index.js +45 -20
- package/dist/routing.js +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,6 @@ It supports all of Solid's SSR methods and has Solid's transitions baked in, so
|
|
|
29
29
|
- [useLocation](#uselocation)
|
|
30
30
|
- [useSearchParams](#usesearchparams)
|
|
31
31
|
- [useIsRouting](#useisrouting)
|
|
32
|
-
- [useRouteData](#useroutedata)
|
|
33
32
|
- [useMatch](#usematch)
|
|
34
33
|
- [useBeforeLeave](#usebeforeleave)
|
|
35
34
|
- [SPAs in Deployed Environments](#spas-in-deployed-environments)
|
|
@@ -490,7 +489,7 @@ You can revalidate the cache using the `revalidate` method or you can set `reval
|
|
|
490
489
|
This is light wrapper over `createResource` that aims to serve as stand-in for a future primitive we intend to bring to Solid core in 2.0. It is a simpler async primitive where the function tracks like `createMemo` and it expects a promise back that it turns into a Signal. Reading it before it is ready causes Suspense/Transitions to trigger.
|
|
491
490
|
|
|
492
491
|
```jsx
|
|
493
|
-
const user = createAsync(() => getUser(params.id))
|
|
492
|
+
const user = createAsync((currentValue) => getUser(params.id))
|
|
494
493
|
```
|
|
495
494
|
|
|
496
495
|
Using `cache` in `createResource` directly won't work properly as the fetcher is not reactive and it won't invalidate properly.
|
|
@@ -674,7 +673,7 @@ render(() => <Router>{route}</Router>, document.getElementById("app"));
|
|
|
674
673
|
|
|
675
674
|
### Hash Mode Router
|
|
676
675
|
|
|
677
|
-
By default, Solid Router uses `location.pathname` as route path. You can simply switch to hash mode through
|
|
676
|
+
By default, Solid Router uses `location.pathname` as route path. You can simply switch to hash mode through using `<HashRouter>`.
|
|
678
677
|
|
|
679
678
|
```jsx
|
|
680
679
|
import { HashRouter } from "@solidjs/router";
|
package/dist/data/cache.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { type ReconcileOptions } from "solid-js/store";
|
|
2
1
|
import { CacheEntry } from "../types.js";
|
|
3
2
|
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
|
|
4
3
|
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
|
|
5
|
-
export type CachedFunction<T extends (...args: any) =>
|
|
6
|
-
keyFor: (...args:
|
|
4
|
+
export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends A ? (...args: never[]) => R : T) & {
|
|
5
|
+
keyFor: (...args: A) => string;
|
|
7
6
|
key: string;
|
|
8
|
-
};
|
|
9
|
-
export declare function cache<T extends (...args: any) =>
|
|
7
|
+
} : never;
|
|
8
|
+
export declare function cache<T extends (...args: any) => any>(fn: T, name: string): CachedFunction<T>;
|
|
10
9
|
export declare namespace cache {
|
|
11
10
|
var set: (key: string, value: any) => void;
|
|
12
11
|
var clear: () => void;
|
package/dist/data/cache.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
|
|
2
|
-
import { createStore, reconcile } from "solid-js/store";
|
|
3
2
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
4
3
|
import { useNavigate, getIntent } from "../routing.js";
|
|
5
4
|
const LocationHeader = "Location";
|
|
@@ -41,8 +40,7 @@ export function cacheKeyOp(key, fn) {
|
|
|
41
40
|
fn(cacheMap.get(k));
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
|
-
export function cache(fn, name
|
|
45
|
-
const [store, setStore] = createStore({});
|
|
43
|
+
export function cache(fn, name) {
|
|
46
44
|
// prioritize GET for server functions
|
|
47
45
|
if (fn.GET)
|
|
48
46
|
fn = fn.GET;
|
|
@@ -99,15 +97,6 @@ export function cache(fn, name, options) {
|
|
|
99
97
|
let res = !isServer && sharedConfig.context && sharedConfig.has(key)
|
|
100
98
|
? sharedConfig.load(key) // hydrating
|
|
101
99
|
: fn(...args);
|
|
102
|
-
// serialize on server
|
|
103
|
-
if (isServer &&
|
|
104
|
-
sharedConfig.context &&
|
|
105
|
-
sharedConfig.context.async &&
|
|
106
|
-
!sharedConfig.context.noHydrate) {
|
|
107
|
-
const e = getRequestEvent();
|
|
108
|
-
e && e.router.dataOnly && (e.router.data[key] = res);
|
|
109
|
-
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
110
|
-
}
|
|
111
100
|
if (cached) {
|
|
112
101
|
cached[0] = now;
|
|
113
102
|
cached[1] = res;
|
|
@@ -122,12 +111,25 @@ export function cache(fn, name, options) {
|
|
|
122
111
|
cached[3].count++;
|
|
123
112
|
cached[3][0](); // track
|
|
124
113
|
}
|
|
114
|
+
if (isServer) {
|
|
115
|
+
const e = getRequestEvent();
|
|
116
|
+
e && e.router.dataOnly && (e.router.data[key] = res);
|
|
117
|
+
return res;
|
|
118
|
+
}
|
|
125
119
|
if (intent !== "preload") {
|
|
126
120
|
res =
|
|
127
121
|
"then" in res
|
|
128
122
|
? res.then(handleResponse(false), handleResponse(true))
|
|
129
123
|
: handleResponse(false)(res);
|
|
130
124
|
}
|
|
125
|
+
// serialize on server
|
|
126
|
+
if (isServer &&
|
|
127
|
+
sharedConfig.context &&
|
|
128
|
+
sharedConfig.context.async &&
|
|
129
|
+
!sharedConfig.context.noHydrate) {
|
|
130
|
+
const e = getRequestEvent();
|
|
131
|
+
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
132
|
+
}
|
|
131
133
|
return res;
|
|
132
134
|
function handleResponse(error) {
|
|
133
135
|
return async (v) => {
|
|
@@ -153,10 +155,7 @@ export function cache(fn, name, options) {
|
|
|
153
155
|
}
|
|
154
156
|
if (error)
|
|
155
157
|
throw v;
|
|
156
|
-
|
|
157
|
-
return v;
|
|
158
|
-
setStore(key, reconcile(v, options));
|
|
159
|
-
return store[key];
|
|
158
|
+
return v;
|
|
160
159
|
};
|
|
161
160
|
}
|
|
162
161
|
});
|
|
@@ -2,13 +2,26 @@
|
|
|
2
2
|
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
|
|
3
3
|
*/
|
|
4
4
|
import { type Accessor } from "solid-js";
|
|
5
|
-
|
|
5
|
+
import { type ReconcileOptions } from "solid-js/store";
|
|
6
|
+
export declare function createAsync<T>(fn: (prev: T) => Promise<T>, options: {
|
|
6
7
|
name?: string;
|
|
7
8
|
initialValue: T;
|
|
8
9
|
deferStream?: boolean;
|
|
9
10
|
}): Accessor<T>;
|
|
10
|
-
export declare function createAsync<T>(fn: () => Promise<T>, options?: {
|
|
11
|
+
export declare function createAsync<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
|
|
11
12
|
name?: string;
|
|
12
13
|
initialValue?: T;
|
|
13
14
|
deferStream?: boolean;
|
|
14
15
|
}): Accessor<T | undefined>;
|
|
16
|
+
export declare function createAsyncStore<T>(fn: (prev: T) => Promise<T>, options: {
|
|
17
|
+
name?: string;
|
|
18
|
+
initialValue: T;
|
|
19
|
+
deferStream?: boolean;
|
|
20
|
+
reconcile?: ReconcileOptions;
|
|
21
|
+
}): Accessor<T>;
|
|
22
|
+
export declare function createAsyncStore<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
|
|
23
|
+
name?: string;
|
|
24
|
+
initialValue?: T;
|
|
25
|
+
deferStream?: boolean;
|
|
26
|
+
reconcile?: ReconcileOptions;
|
|
27
|
+
}): Accessor<T | undefined>;
|
package/dist/data/createAsync.js
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
|
|
3
3
|
*/
|
|
4
|
-
import { createResource, sharedConfig } from "solid-js";
|
|
4
|
+
import { createResource, sharedConfig, untrack } from "solid-js";
|
|
5
|
+
import { createStore, reconcile, unwrap } from "solid-js/store";
|
|
5
6
|
import { isServer } from "solid-js/web";
|
|
6
7
|
export function createAsync(fn, options) {
|
|
7
|
-
|
|
8
|
+
let resource;
|
|
9
|
+
let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
|
|
10
|
+
[resource] = createResource(() => subFetch(fn, untrack(prev)), v => v, options);
|
|
8
11
|
return () => resource();
|
|
9
12
|
}
|
|
13
|
+
export function createAsyncStore(fn, options = {}) {
|
|
14
|
+
let resource;
|
|
15
|
+
let prev = () => !resource || resource.state === "unresolved" ? undefined : unwrap(resource.latest);
|
|
16
|
+
[resource] = createResource(() => subFetch(fn, untrack(prev)), v => v, {
|
|
17
|
+
...options,
|
|
18
|
+
storage: (init) => createDeepSignal(init, options.reconcile)
|
|
19
|
+
});
|
|
20
|
+
return () => resource();
|
|
21
|
+
}
|
|
22
|
+
function createDeepSignal(value, options) {
|
|
23
|
+
const [store, setStore] = createStore({
|
|
24
|
+
value
|
|
25
|
+
});
|
|
26
|
+
return [
|
|
27
|
+
() => store.value,
|
|
28
|
+
(v) => {
|
|
29
|
+
typeof v === "function" && (v = v());
|
|
30
|
+
setStore("value", reconcile(v, options));
|
|
31
|
+
return store.value;
|
|
32
|
+
}
|
|
33
|
+
];
|
|
34
|
+
}
|
|
10
35
|
// mock promise while hydrating to prevent fetching
|
|
11
36
|
class MockPromise {
|
|
12
37
|
static all() {
|
|
@@ -37,15 +62,15 @@ class MockPromise {
|
|
|
37
62
|
return new MockPromise();
|
|
38
63
|
}
|
|
39
64
|
}
|
|
40
|
-
function subFetch(fn) {
|
|
65
|
+
function subFetch(fn, prev) {
|
|
41
66
|
if (isServer || !sharedConfig.context)
|
|
42
|
-
return fn();
|
|
67
|
+
return fn(prev);
|
|
43
68
|
const ogFetch = fetch;
|
|
44
69
|
const ogPromise = Promise;
|
|
45
70
|
try {
|
|
46
71
|
window.fetch = () => new MockPromise();
|
|
47
72
|
Promise = MockPromise;
|
|
48
|
-
return fn();
|
|
73
|
+
return fn(prev);
|
|
49
74
|
}
|
|
50
75
|
finally {
|
|
51
76
|
window.fetch = ogFetch;
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createAsync } from "./createAsync.js";
|
|
1
|
+
export { createAsync, createAsyncStore } from "./createAsync.js";
|
|
2
2
|
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
|
|
3
3
|
export { cache, revalidate, type CachedFunction } from "./cache.js";
|
|
4
4
|
export { redirect, reload, json } from "./response.js";
|
package/dist/data/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createAsync } from "./createAsync.js";
|
|
1
|
+
export { createAsync, createAsyncStore } from "./createAsync.js";
|
|
2
2
|
export { action, useSubmission, useSubmissions, useAction } from "./action.js";
|
|
3
3
|
export { cache, revalidate } from "./cache.js";
|
|
4
4
|
export { redirect, reload, json } from "./response.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isServer, getRequestEvent, createComponent as createComponent$1, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
|
|
2
2
|
import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, startTransition, resetErrorBoundaries, createComponent, children, mergeProps, createRoot, Show, getListener, sharedConfig, $TRACK, splitProps, createResource } from 'solid-js';
|
|
3
|
-
import { createStore, reconcile } from 'solid-js/store';
|
|
3
|
+
import { createStore, reconcile, unwrap } from 'solid-js/store';
|
|
4
4
|
|
|
5
5
|
function createBeforeLeave() {
|
|
6
6
|
let listeners = new Set();
|
|
@@ -467,6 +467,7 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
467
467
|
}
|
|
468
468
|
});
|
|
469
469
|
});
|
|
470
|
+
const owner = getOwner();
|
|
470
471
|
return {
|
|
471
472
|
base: baseRoute,
|
|
472
473
|
location,
|
|
@@ -577,7 +578,10 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
577
578
|
params
|
|
578
579
|
} = matches[match];
|
|
579
580
|
route.component && route.component.preload && route.component.preload();
|
|
580
|
-
|
|
581
|
+
const {
|
|
582
|
+
load
|
|
583
|
+
} = route;
|
|
584
|
+
preloadData && load && runWithOwner(owner, () => load({
|
|
581
585
|
params,
|
|
582
586
|
location: {
|
|
583
587
|
pathname: url.pathname,
|
|
@@ -588,7 +592,7 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
588
592
|
key: ""
|
|
589
593
|
},
|
|
590
594
|
intent: "preload"
|
|
591
|
-
});
|
|
595
|
+
}));
|
|
592
596
|
}
|
|
593
597
|
intent = prevIntent;
|
|
594
598
|
}
|
|
@@ -879,8 +883,7 @@ function cacheKeyOp(key, fn) {
|
|
|
879
883
|
if (key === undefined || matchKey(k, key)) fn(cacheMap.get(k));
|
|
880
884
|
}
|
|
881
885
|
}
|
|
882
|
-
function cache(fn, name
|
|
883
|
-
const [store, setStore] = createStore({});
|
|
886
|
+
function cache(fn, name) {
|
|
884
887
|
// prioritize GET for server functions
|
|
885
888
|
if (fn.GET) fn = fn.GET;
|
|
886
889
|
const cachedFn = (...args) => {
|
|
@@ -927,13 +930,6 @@ function cache(fn, name, options) {
|
|
|
927
930
|
}
|
|
928
931
|
let res = !isServer && sharedConfig.context && sharedConfig.has(key) ? sharedConfig.load(key) // hydrating
|
|
929
932
|
: fn(...args);
|
|
930
|
-
|
|
931
|
-
// serialize on server
|
|
932
|
-
if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
|
|
933
|
-
const e = getRequestEvent();
|
|
934
|
-
e && e.router.dataOnly && (e.router.data[key] = res);
|
|
935
|
-
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
936
|
-
}
|
|
937
933
|
if (cached) {
|
|
938
934
|
cached[0] = now;
|
|
939
935
|
cached[1] = res;
|
|
@@ -947,9 +943,19 @@ function cache(fn, name, options) {
|
|
|
947
943
|
cached[3].count++;
|
|
948
944
|
cached[3][0](); // track
|
|
949
945
|
}
|
|
946
|
+
if (isServer) {
|
|
947
|
+
const e = getRequestEvent();
|
|
948
|
+
e && e.router.dataOnly && (e.router.data[key] = res);
|
|
949
|
+
return res;
|
|
950
|
+
}
|
|
950
951
|
if (intent !== "preload") {
|
|
951
952
|
res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res);
|
|
952
953
|
}
|
|
954
|
+
// serialize on server
|
|
955
|
+
if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
|
|
956
|
+
const e = getRequestEvent();
|
|
957
|
+
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
958
|
+
}
|
|
953
959
|
return res;
|
|
954
960
|
function handleResponse(error) {
|
|
955
961
|
return async v => {
|
|
@@ -972,9 +978,7 @@ function cache(fn, name, options) {
|
|
|
972
978
|
if (v.customBody) v = await v.customBody();
|
|
973
979
|
}
|
|
974
980
|
if (error) throw v;
|
|
975
|
-
|
|
976
|
-
setStore(key, reconcile(v, options));
|
|
977
|
-
return store[key];
|
|
981
|
+
return v;
|
|
978
982
|
};
|
|
979
983
|
}
|
|
980
984
|
};
|
|
@@ -1447,9 +1451,30 @@ function Navigate(props) {
|
|
|
1447
1451
|
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
|
|
1448
1452
|
*/
|
|
1449
1453
|
function createAsync(fn, options) {
|
|
1450
|
-
|
|
1454
|
+
let resource;
|
|
1455
|
+
let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
|
|
1456
|
+
[resource] = createResource(() => subFetch(fn, untrack(prev)), v => v, options);
|
|
1451
1457
|
return () => resource();
|
|
1452
1458
|
}
|
|
1459
|
+
function createAsyncStore(fn, options = {}) {
|
|
1460
|
+
let resource;
|
|
1461
|
+
let prev = () => !resource || resource.state === "unresolved" ? undefined : unwrap(resource.latest);
|
|
1462
|
+
[resource] = createResource(() => subFetch(fn, untrack(prev)), v => v, {
|
|
1463
|
+
...options,
|
|
1464
|
+
storage: init => createDeepSignal(init, options.reconcile)
|
|
1465
|
+
});
|
|
1466
|
+
return () => resource();
|
|
1467
|
+
}
|
|
1468
|
+
function createDeepSignal(value, options) {
|
|
1469
|
+
const [store, setStore] = createStore({
|
|
1470
|
+
value
|
|
1471
|
+
});
|
|
1472
|
+
return [() => store.value, v => {
|
|
1473
|
+
typeof v === "function" && (v = v());
|
|
1474
|
+
setStore("value", reconcile(v, options));
|
|
1475
|
+
return store.value;
|
|
1476
|
+
}];
|
|
1477
|
+
}
|
|
1453
1478
|
|
|
1454
1479
|
// mock promise while hydrating to prevent fetching
|
|
1455
1480
|
class MockPromise {
|
|
@@ -1481,14 +1506,14 @@ class MockPromise {
|
|
|
1481
1506
|
return new MockPromise();
|
|
1482
1507
|
}
|
|
1483
1508
|
}
|
|
1484
|
-
function subFetch(fn) {
|
|
1485
|
-
if (isServer || !sharedConfig.context) return fn();
|
|
1509
|
+
function subFetch(fn, prev) {
|
|
1510
|
+
if (isServer || !sharedConfig.context) return fn(prev);
|
|
1486
1511
|
const ogFetch = fetch;
|
|
1487
1512
|
const ogPromise = Promise;
|
|
1488
1513
|
try {
|
|
1489
1514
|
window.fetch = () => new MockPromise();
|
|
1490
1515
|
Promise = MockPromise;
|
|
1491
|
-
return fn();
|
|
1516
|
+
return fn(prev);
|
|
1492
1517
|
} finally {
|
|
1493
1518
|
window.fetch = ogFetch;
|
|
1494
1519
|
Promise = ogPromise;
|
|
@@ -1548,4 +1573,4 @@ function json(data, init = {}) {
|
|
|
1548
1573
|
return response;
|
|
1549
1574
|
}
|
|
1550
1575
|
|
|
1551
|
-
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|
|
1576
|
+
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|
package/dist/routing.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getOwner, runWithOwner } from "solid-js";
|
|
1
2
|
import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
|
|
2
3
|
import { isServer, getRequestEvent } from "solid-js/web";
|
|
3
4
|
import { createBeforeLeave } from "./lifecycle.js";
|
|
@@ -236,6 +237,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
236
237
|
}
|
|
237
238
|
});
|
|
238
239
|
});
|
|
240
|
+
const owner = getOwner();
|
|
239
241
|
return {
|
|
240
242
|
base: baseRoute,
|
|
241
243
|
location,
|
|
@@ -331,9 +333,10 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
331
333
|
route.component &&
|
|
332
334
|
route.component.preload &&
|
|
333
335
|
route.component.preload();
|
|
336
|
+
const { load } = route;
|
|
334
337
|
preloadData &&
|
|
335
|
-
|
|
336
|
-
|
|
338
|
+
load &&
|
|
339
|
+
runWithOwner(owner, () => load({
|
|
337
340
|
params,
|
|
338
341
|
location: {
|
|
339
342
|
pathname: url.pathname,
|
|
@@ -344,7 +347,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
344
347
|
key: ""
|
|
345
348
|
},
|
|
346
349
|
intent: "preload"
|
|
347
|
-
});
|
|
350
|
+
}));
|
|
348
351
|
}
|
|
349
352
|
intent = prevIntent;
|
|
350
353
|
}
|