svelte 5.41.0 → 5.41.2
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/compiler/index.js +1 -1
- package/package.json +1 -1
- package/src/compiler/phases/2-analyze/index.js +3 -3
- package/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +13 -6
- package/src/compiler/phases/2-analyze/visitors/CallExpression.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/ConstTag.js +3 -1
- package/src/compiler/phases/2-analyze/visitors/EachBlock.js +2 -1
- package/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js +0 -6
- package/src/compiler/phases/3-transform/client/transform-client.js +4 -1
- package/src/compiler/phases/3-transform/client/visitors/CallExpression.js +21 -3
- package/src/compiler/phases/3-transform/client/visitors/Fragment.js +7 -2
- package/src/compiler/phases/3-transform/client/visitors/LetDirective.js +21 -17
- package/src/compiler/phases/3-transform/client/visitors/RegularElement.js +1 -1
- package/src/compiler/phases/3-transform/client/visitors/SlotElement.js +1 -1
- package/src/compiler/phases/3-transform/client/visitors/SvelteFragment.js +1 -1
- package/src/compiler/phases/3-transform/client/visitors/shared/component.js +2 -2
- package/src/compiler/phases/3-transform/server/visitors/CallExpression.js +10 -4
- package/src/compiler/phases/3-transform/utils.js +14 -25
- package/src/internal/client/dev/inspect.js +14 -4
- package/src/internal/client/dev/tracing.js +10 -1
- package/src/internal/client/dom/blocks/async.js +5 -0
- package/src/internal/client/dom/blocks/await.js +71 -137
- package/src/internal/client/dom/blocks/boundary.js +7 -26
- package/src/internal/client/dom/blocks/branches.js +185 -0
- package/src/internal/client/dom/blocks/if.js +28 -107
- package/src/internal/client/dom/blocks/key.js +12 -58
- package/src/internal/client/dom/blocks/snippet.js +6 -22
- package/src/internal/client/dom/blocks/svelte-component.js +7 -63
- package/src/internal/client/dom/blocks/svelte-element.js +34 -45
- package/src/internal/client/reactivity/async.js +27 -16
- package/src/internal/client/reactivity/batch.js +134 -69
- package/src/internal/client/reactivity/deriveds.js +19 -10
- package/src/internal/client/reactivity/effects.js +20 -2
- package/src/internal/client/reactivity/sources.js +1 -1
- package/src/internal/server/index.js +0 -9
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
/** @import {
|
|
2
|
-
/** @import { Batch } from '../../reactivity/batch.js'; */
|
|
3
|
-
import { UNINITIALIZED } from '../../../../constants.js';
|
|
4
|
-
import { block, branch, pause_effect } from '../../reactivity/effects.js';
|
|
5
|
-
import { not_equal, safe_not_equal } from '../../reactivity/equality.js';
|
|
1
|
+
/** @import { TemplateNode } from '#client' */
|
|
6
2
|
import { is_runes } from '../../context.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
3
|
+
import { block } from '../../reactivity/effects.js';
|
|
4
|
+
import { hydrate_next, hydrating } from '../hydration.js';
|
|
5
|
+
import { BranchManager } from './branches.js';
|
|
10
6
|
|
|
11
7
|
/**
|
|
12
8
|
* @template V
|
|
@@ -20,60 +16,18 @@ export function key(node, get_key, render_fn) {
|
|
|
20
16
|
hydrate_next();
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
var
|
|
19
|
+
var branches = new BranchManager(node);
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
var key = UNINITIALIZED;
|
|
27
|
-
|
|
28
|
-
/** @type {Effect} */
|
|
29
|
-
var effect;
|
|
30
|
-
|
|
31
|
-
/** @type {Effect} */
|
|
32
|
-
var pending_effect;
|
|
33
|
-
|
|
34
|
-
/** @type {DocumentFragment | null} */
|
|
35
|
-
var offscreen_fragment = null;
|
|
36
|
-
|
|
37
|
-
var changed = is_runes() ? not_equal : safe_not_equal;
|
|
38
|
-
|
|
39
|
-
function commit() {
|
|
40
|
-
if (effect) {
|
|
41
|
-
pause_effect(effect);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (offscreen_fragment !== null) {
|
|
45
|
-
// remove the anchor
|
|
46
|
-
/** @type {Text} */ (offscreen_fragment.lastChild).remove();
|
|
47
|
-
|
|
48
|
-
anchor.before(offscreen_fragment);
|
|
49
|
-
offscreen_fragment = null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
effect = pending_effect;
|
|
53
|
-
}
|
|
21
|
+
var legacy = !is_runes();
|
|
54
22
|
|
|
55
23
|
block(() => {
|
|
56
|
-
|
|
57
|
-
var target = anchor;
|
|
58
|
-
|
|
59
|
-
var defer = should_defer_append();
|
|
60
|
-
|
|
61
|
-
if (defer) {
|
|
62
|
-
offscreen_fragment = document.createDocumentFragment();
|
|
63
|
-
offscreen_fragment.append((target = create_text()));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
pending_effect = branch(() => render_fn(target));
|
|
24
|
+
var key = get_key();
|
|
67
25
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
commit();
|
|
72
|
-
}
|
|
26
|
+
// key blocks in Svelte <5 had stupid semantics
|
|
27
|
+
if (legacy && key !== null && typeof key === 'object') {
|
|
28
|
+
key = /** @type {V} */ ({});
|
|
73
29
|
}
|
|
74
|
-
});
|
|
75
30
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
31
|
+
branches.ensure(key, render_fn);
|
|
32
|
+
});
|
|
79
33
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** @import { Snippet } from 'svelte' */
|
|
2
|
-
/** @import {
|
|
2
|
+
/** @import { TemplateNode } from '#client' */
|
|
3
3
|
/** @import { Getters } from '#shared' */
|
|
4
4
|
import { EFFECT_TRANSPARENT, ELEMENT_NODE } from '#client/constants';
|
|
5
|
-
import {
|
|
5
|
+
import { block, teardown } from '../../reactivity/effects.js';
|
|
6
6
|
import {
|
|
7
7
|
dev_current_component_function,
|
|
8
8
|
set_dev_current_component_function
|
|
@@ -14,8 +14,8 @@ import * as w from '../../warnings.js';
|
|
|
14
14
|
import * as e from '../../errors.js';
|
|
15
15
|
import { DEV } from 'esm-env';
|
|
16
16
|
import { get_first_child, get_next_sibling } from '../operations.js';
|
|
17
|
-
import { noop } from '../../../shared/utils.js';
|
|
18
17
|
import { prevent_snippet_stringification } from '../../../shared/validate.js';
|
|
18
|
+
import { BranchManager } from './branches.js';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @template {(node: TemplateNode, ...args: any[]) => void} SnippetFn
|
|
@@ -25,33 +25,17 @@ import { prevent_snippet_stringification } from '../../../shared/validate.js';
|
|
|
25
25
|
* @returns {void}
|
|
26
26
|
*/
|
|
27
27
|
export function snippet(node, get_snippet, ...args) {
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
/** @type {SnippetFn | null | undefined} */
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
var snippet = noop;
|
|
33
|
-
|
|
34
|
-
/** @type {Effect | null} */
|
|
35
|
-
var snippet_effect;
|
|
28
|
+
var branches = new BranchManager(node);
|
|
36
29
|
|
|
37
30
|
block(() => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (snippet_effect) {
|
|
41
|
-
destroy_effect(snippet_effect);
|
|
42
|
-
snippet_effect = null;
|
|
43
|
-
}
|
|
31
|
+
const snippet = get_snippet() ?? null;
|
|
44
32
|
|
|
45
33
|
if (DEV && snippet == null) {
|
|
46
34
|
e.invalid_snippet();
|
|
47
35
|
}
|
|
48
36
|
|
|
49
|
-
|
|
37
|
+
branches.ensure(snippet, snippet && ((anchor) => snippet(anchor, ...args)));
|
|
50
38
|
}, EFFECT_TRANSPARENT);
|
|
51
|
-
|
|
52
|
-
if (hydrating) {
|
|
53
|
-
anchor = hydrate_node;
|
|
54
|
-
}
|
|
55
39
|
}
|
|
56
40
|
|
|
57
41
|
/**
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
/** @import { TemplateNode, Dom
|
|
2
|
-
/** @import { Batch } from '../../reactivity/batch.js'; */
|
|
1
|
+
/** @import { TemplateNode, Dom } from '#client' */
|
|
3
2
|
import { EFFECT_TRANSPARENT } from '#client/constants';
|
|
4
|
-
import { block
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { create_text, should_defer_append } from '../operations.js';
|
|
3
|
+
import { block } from '../../reactivity/effects.js';
|
|
4
|
+
import { hydrate_next, hydrating } from '../hydration.js';
|
|
5
|
+
import { BranchManager } from './branches.js';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* @template P
|
|
@@ -19,64 +17,10 @@ export function component(node, get_component, render_fn) {
|
|
|
19
17
|
hydrate_next();
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
/** @type {C} */
|
|
25
|
-
var component;
|
|
26
|
-
|
|
27
|
-
/** @type {Effect | null} */
|
|
28
|
-
var effect;
|
|
29
|
-
|
|
30
|
-
/** @type {DocumentFragment | null} */
|
|
31
|
-
var offscreen_fragment = null;
|
|
32
|
-
|
|
33
|
-
/** @type {Effect | null} */
|
|
34
|
-
var pending_effect = null;
|
|
35
|
-
|
|
36
|
-
function commit() {
|
|
37
|
-
if (effect) {
|
|
38
|
-
pause_effect(effect);
|
|
39
|
-
effect = null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (offscreen_fragment) {
|
|
43
|
-
// remove the anchor
|
|
44
|
-
/** @type {Text} */ (offscreen_fragment.lastChild).remove();
|
|
45
|
-
|
|
46
|
-
anchor.before(offscreen_fragment);
|
|
47
|
-
offscreen_fragment = null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
effect = pending_effect;
|
|
51
|
-
pending_effect = null;
|
|
52
|
-
}
|
|
20
|
+
var branches = new BranchManager(node);
|
|
53
21
|
|
|
54
22
|
block(() => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
var defer = should_defer_append();
|
|
58
|
-
|
|
59
|
-
if (component) {
|
|
60
|
-
var target = anchor;
|
|
61
|
-
|
|
62
|
-
if (defer) {
|
|
63
|
-
offscreen_fragment = document.createDocumentFragment();
|
|
64
|
-
offscreen_fragment.append((target = create_text()));
|
|
65
|
-
if (effect) {
|
|
66
|
-
/** @type {Batch} */ (current_batch).skipped_effects.add(effect);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
pending_effect = branch(() => render_fn(target, component));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (defer) {
|
|
73
|
-
/** @type {Batch} */ (current_batch).add_callback(commit);
|
|
74
|
-
} else {
|
|
75
|
-
commit();
|
|
76
|
-
}
|
|
23
|
+
var component = get_component() ?? null;
|
|
24
|
+
branches.ensure(component, component && ((target) => render_fn(target, component)));
|
|
77
25
|
}, EFFECT_TRANSPARENT);
|
|
78
|
-
|
|
79
|
-
if (hydrating) {
|
|
80
|
-
anchor = hydrate_node;
|
|
81
|
-
}
|
|
82
26
|
}
|
|
@@ -8,13 +8,7 @@ import {
|
|
|
8
8
|
set_hydrating
|
|
9
9
|
} from '../hydration.js';
|
|
10
10
|
import { create_text, get_first_child } from '../operations.js';
|
|
11
|
-
import {
|
|
12
|
-
block,
|
|
13
|
-
branch,
|
|
14
|
-
destroy_effect,
|
|
15
|
-
pause_effect,
|
|
16
|
-
resume_effect
|
|
17
|
-
} from '../../reactivity/effects.js';
|
|
11
|
+
import { block, teardown } from '../../reactivity/effects.js';
|
|
18
12
|
import { set_should_intro } from '../../render.js';
|
|
19
13
|
import { current_each_item, set_current_each_item } from './each.js';
|
|
20
14
|
import { active_effect } from '../../runtime.js';
|
|
@@ -23,6 +17,7 @@ import { DEV } from 'esm-env';
|
|
|
23
17
|
import { EFFECT_TRANSPARENT, ELEMENT_NODE } from '#client/constants';
|
|
24
18
|
import { assign_nodes } from '../template.js';
|
|
25
19
|
import { is_raw_text_element } from '../../../../utils.js';
|
|
20
|
+
import { BranchManager } from './branches.js';
|
|
26
21
|
|
|
27
22
|
/**
|
|
28
23
|
* @param {Comment | Element} node
|
|
@@ -42,12 +37,6 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
|
|
|
42
37
|
|
|
43
38
|
var filename = DEV && location && component_context?.function[FILENAME];
|
|
44
39
|
|
|
45
|
-
/** @type {string | null} */
|
|
46
|
-
var tag;
|
|
47
|
-
|
|
48
|
-
/** @type {string | null} */
|
|
49
|
-
var current_tag;
|
|
50
|
-
|
|
51
40
|
/** @type {null | Element} */
|
|
52
41
|
var element = null;
|
|
53
42
|
|
|
@@ -58,9 +47,6 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
|
|
|
58
47
|
|
|
59
48
|
var anchor = /** @type {TemplateNode} */ (hydrating ? hydrate_node : node);
|
|
60
49
|
|
|
61
|
-
/** @type {Effect | null} */
|
|
62
|
-
var effect;
|
|
63
|
-
|
|
64
50
|
/**
|
|
65
51
|
* The keyed `{#each ...}` item block, if any, that this element is inside.
|
|
66
52
|
* We track this so we can set it when changing the element, allowing any
|
|
@@ -68,36 +54,24 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
|
|
|
68
54
|
*/
|
|
69
55
|
var each_item_block = current_each_item;
|
|
70
56
|
|
|
57
|
+
var branches = new BranchManager(anchor, false);
|
|
58
|
+
|
|
71
59
|
block(() => {
|
|
72
60
|
const next_tag = get_tag() || null;
|
|
73
61
|
var ns = get_namespace ? get_namespace() : is_svg || next_tag === 'svg' ? NAMESPACE_SVG : null;
|
|
74
62
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
var previous_each_item = current_each_item;
|
|
80
|
-
set_current_each_item(each_item_block);
|
|
81
|
-
|
|
82
|
-
if (effect) {
|
|
83
|
-
if (next_tag === null) {
|
|
84
|
-
// start outro
|
|
85
|
-
pause_effect(effect, () => {
|
|
86
|
-
effect = null;
|
|
87
|
-
current_tag = null;
|
|
88
|
-
});
|
|
89
|
-
} else if (next_tag === current_tag) {
|
|
90
|
-
// same tag as is currently rendered — abort outro
|
|
91
|
-
resume_effect(effect);
|
|
92
|
-
} else {
|
|
93
|
-
// tag is changing — destroy immediately, render contents without intro transitions
|
|
94
|
-
destroy_effect(effect);
|
|
95
|
-
set_should_intro(false);
|
|
96
|
-
}
|
|
63
|
+
if (next_tag === null) {
|
|
64
|
+
branches.ensure(null, null);
|
|
65
|
+
set_should_intro(true);
|
|
66
|
+
return;
|
|
97
67
|
}
|
|
98
68
|
|
|
99
|
-
|
|
100
|
-
|
|
69
|
+
branches.ensure(next_tag, (anchor) => {
|
|
70
|
+
// See explanation of `each_item_block` above
|
|
71
|
+
var previous_each_item = current_each_item;
|
|
72
|
+
set_current_each_item(each_item_block);
|
|
73
|
+
|
|
74
|
+
if (next_tag) {
|
|
101
75
|
element = hydrating
|
|
102
76
|
? /** @type {Element} */ (element)
|
|
103
77
|
: ns
|
|
@@ -149,16 +123,31 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
|
|
|
149
123
|
/** @type {Effect} */ (active_effect).nodes_end = element;
|
|
150
124
|
|
|
151
125
|
anchor.before(element);
|
|
152
|
-
}
|
|
153
|
-
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
set_current_each_item(previous_each_item);
|
|
129
|
+
|
|
130
|
+
if (hydrating) {
|
|
131
|
+
set_hydrate_node(anchor);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
154
134
|
|
|
155
|
-
|
|
156
|
-
if (tag) current_tag = tag;
|
|
135
|
+
// revert to the default state after the effect has been created
|
|
157
136
|
set_should_intro(true);
|
|
158
137
|
|
|
159
|
-
|
|
138
|
+
return () => {
|
|
139
|
+
if (next_tag) {
|
|
140
|
+
// if we're in this callback because we're re-running the effect,
|
|
141
|
+
// disable intros (unless no element is currently displayed)
|
|
142
|
+
set_should_intro(false);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
160
145
|
}, EFFECT_TRANSPARENT);
|
|
161
146
|
|
|
147
|
+
teardown(() => {
|
|
148
|
+
set_should_intro(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
162
151
|
if (was_hydrating) {
|
|
163
152
|
set_hydrating(true);
|
|
164
153
|
set_hydrate_node(anchor);
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
/** @import { Effect, Value } from '#client' */
|
|
2
|
-
|
|
1
|
+
/** @import { Effect, TemplateNode, Value } from '#client' */
|
|
3
2
|
import { DESTROYED } from '#client/constants';
|
|
4
3
|
import { DEV } from 'esm-env';
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
component_context,
|
|
6
|
+
dev_stack,
|
|
7
|
+
is_runes,
|
|
8
|
+
set_component_context,
|
|
9
|
+
set_dev_stack
|
|
10
|
+
} from '../context.js';
|
|
6
11
|
import { get_boundary } from '../dom/blocks/boundary.js';
|
|
7
12
|
import { invoke_error_boundary } from '../error-handling.js';
|
|
8
13
|
import {
|
|
@@ -28,6 +33,7 @@ import {
|
|
|
28
33
|
set_hydrating,
|
|
29
34
|
skip_nodes
|
|
30
35
|
} from '../dom/hydration.js';
|
|
36
|
+
import { create_text } from '../dom/operations.js';
|
|
31
37
|
|
|
32
38
|
/**
|
|
33
39
|
*
|
|
@@ -80,7 +86,7 @@ export function flatten(sync, async, fn) {
|
|
|
80
86
|
* some asynchronous work has happened (so that e.g. `await a + b`
|
|
81
87
|
* causes `b` to be registered as a dependency).
|
|
82
88
|
*/
|
|
83
|
-
function capture() {
|
|
89
|
+
export function capture() {
|
|
84
90
|
var previous_effect = active_effect;
|
|
85
91
|
var previous_reaction = active_reaction;
|
|
86
92
|
var previous_component_context = component_context;
|
|
@@ -92,6 +98,10 @@ function capture() {
|
|
|
92
98
|
var previous_hydrate_node = hydrate_node;
|
|
93
99
|
}
|
|
94
100
|
|
|
101
|
+
if (DEV) {
|
|
102
|
+
var previous_dev_stack = dev_stack;
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
return function restore() {
|
|
96
106
|
set_active_effect(previous_effect);
|
|
97
107
|
set_active_reaction(previous_reaction);
|
|
@@ -105,6 +115,7 @@ function capture() {
|
|
|
105
115
|
|
|
106
116
|
if (DEV) {
|
|
107
117
|
set_from_async_derived(null);
|
|
118
|
+
set_dev_stack(previous_dev_stack);
|
|
108
119
|
}
|
|
109
120
|
};
|
|
110
121
|
}
|
|
@@ -193,19 +204,24 @@ export function unset_context() {
|
|
|
193
204
|
set_active_effect(null);
|
|
194
205
|
set_active_reaction(null);
|
|
195
206
|
set_component_context(null);
|
|
196
|
-
|
|
207
|
+
|
|
208
|
+
if (DEV) {
|
|
209
|
+
set_from_async_derived(null);
|
|
210
|
+
set_dev_stack(null);
|
|
211
|
+
}
|
|
197
212
|
}
|
|
198
213
|
|
|
199
214
|
/**
|
|
200
|
-
* @param {
|
|
215
|
+
* @param {TemplateNode} anchor
|
|
216
|
+
* @param {(target: TemplateNode) => Promise<void>} fn
|
|
201
217
|
*/
|
|
202
|
-
export async function async_body(fn) {
|
|
218
|
+
export async function async_body(anchor, fn) {
|
|
203
219
|
var boundary = get_boundary();
|
|
204
220
|
var batch = /** @type {Batch} */ (current_batch);
|
|
205
|
-
var
|
|
221
|
+
var blocking = !boundary.is_pending();
|
|
206
222
|
|
|
207
223
|
boundary.update_pending_count(1);
|
|
208
|
-
|
|
224
|
+
batch.increment(blocking);
|
|
209
225
|
|
|
210
226
|
var active = /** @type {Effect} */ (active_effect);
|
|
211
227
|
|
|
@@ -218,7 +234,7 @@ export async function async_body(fn) {
|
|
|
218
234
|
}
|
|
219
235
|
|
|
220
236
|
try {
|
|
221
|
-
var promise = fn();
|
|
237
|
+
var promise = fn(anchor);
|
|
222
238
|
} finally {
|
|
223
239
|
if (next_hydrate_node) {
|
|
224
240
|
set_hydrate_node(next_hydrate_node);
|
|
@@ -238,12 +254,7 @@ export async function async_body(fn) {
|
|
|
238
254
|
}
|
|
239
255
|
|
|
240
256
|
boundary.update_pending_count(-1);
|
|
241
|
-
|
|
242
|
-
if (pending) {
|
|
243
|
-
batch.flush();
|
|
244
|
-
} else {
|
|
245
|
-
batch.decrement();
|
|
246
|
-
}
|
|
257
|
+
batch.decrement(blocking);
|
|
247
258
|
|
|
248
259
|
unset_context();
|
|
249
260
|
}
|