happy-dom 9.8.2 → 9.8.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/lib/nodes/document/Document.d.ts +1 -1
- package/lib/nodes/document/Document.d.ts.map +1 -1
- package/lib/nodes/document/Document.js +6 -6
- package/lib/nodes/document/Document.js.map +1 -1
- package/lib/nodes/document-fragment/DocumentFragment.d.ts +1 -1
- package/lib/nodes/document-fragment/DocumentFragment.d.ts.map +1 -1
- package/lib/nodes/document-fragment/DocumentFragment.js +6 -6
- package/lib/nodes/document-fragment/DocumentFragment.js.map +1 -1
- package/lib/nodes/element/Element.js +6 -6
- package/lib/nodes/element/Element.js.map +1 -1
- package/lib/nodes/element/ElementUtility.d.ts +20 -9
- package/lib/nodes/element/ElementUtility.d.ts.map +1 -1
- package/lib/nodes/element/ElementUtility.js +54 -22
- package/lib/nodes/element/ElementUtility.js.map +1 -1
- package/lib/nodes/html-select-element/HTMLOptionsCollection.js.map +1 -1
- package/lib/nodes/node/Node.d.ts +1 -1
- package/lib/nodes/node/Node.d.ts.map +1 -1
- package/lib/nodes/node/Node.js +4 -111
- package/lib/nodes/node/Node.js.map +1 -1
- package/lib/nodes/node/NodeUtility.d.ts +37 -12
- package/lib/nodes/node/NodeUtility.d.ts.map +1 -1
- package/lib/nodes/node/NodeUtility.js +174 -30
- package/lib/nodes/node/NodeUtility.js.map +1 -1
- package/package.json +1 -1
- package/src/nodes/document/Document.ts +9 -9
- package/src/nodes/document-fragment/DocumentFragment.ts +9 -9
- package/src/nodes/element/Element.ts +6 -6
- package/src/nodes/element/ElementUtility.ts +77 -27
- package/src/nodes/html-select-element/HTMLOptionsCollection.ts +1 -1
- package/src/nodes/node/Node.ts +5 -142
- package/src/nodes/node/NodeUtility.ts +239 -37
|
@@ -154,24 +154,24 @@ export default class DocumentFragment extends Node implements IDocumentFragment
|
|
|
154
154
|
/**
|
|
155
155
|
* @override
|
|
156
156
|
*/
|
|
157
|
-
public appendChild(node: INode): INode {
|
|
158
|
-
ElementUtility.
|
|
159
|
-
return
|
|
157
|
+
public override appendChild(node: INode): INode {
|
|
158
|
+
// We do not call super here as this will be handled by ElementUtility to improve performance by avoiding validation and other checks.
|
|
159
|
+
return ElementUtility.appendChild(this, node);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
163
|
* @override
|
|
164
164
|
*/
|
|
165
|
-
public removeChild(node: INode): INode {
|
|
166
|
-
ElementUtility.
|
|
167
|
-
return
|
|
165
|
+
public override removeChild(node: INode): INode {
|
|
166
|
+
// We do not call super here as this will be handled by ElementUtility to improve performance by avoiding validation and other checks.
|
|
167
|
+
return ElementUtility.removeChild(this, node);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
171
|
* @override
|
|
172
172
|
*/
|
|
173
|
-
public insertBefore(newNode: INode, referenceNode
|
|
174
|
-
|
|
175
|
-
return
|
|
173
|
+
public override insertBefore(newNode: INode, referenceNode: INode | null): INode {
|
|
174
|
+
// We do not call super here as this will be handled by ElementUtility to improve performance by avoiding validation and other checks.
|
|
175
|
+
return ElementUtility.insertBefore(this, newNode, referenceNode);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
@@ -370,24 +370,24 @@ export default class Element extends Node implements IElement {
|
|
|
370
370
|
* @override
|
|
371
371
|
*/
|
|
372
372
|
public override appendChild(node: INode): INode {
|
|
373
|
-
ElementUtility.
|
|
374
|
-
return
|
|
373
|
+
// We do not call super here as this will be handled by ElementUtility to improve performance by avoiding validation and other checks.
|
|
374
|
+
return ElementUtility.appendChild(this, node);
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
/**
|
|
378
378
|
* @override
|
|
379
379
|
*/
|
|
380
380
|
public override removeChild(node: INode): INode {
|
|
381
|
-
ElementUtility.
|
|
382
|
-
return
|
|
381
|
+
// We do not call super here as this will be handled by ElementUtility to improve performance by avoiding validation and other checks.
|
|
382
|
+
return ElementUtility.removeChild(this, node);
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
/**
|
|
386
386
|
* @override
|
|
387
387
|
*/
|
|
388
388
|
public override insertBefore(newNode: INode, referenceNode: INode | null): INode {
|
|
389
|
-
|
|
390
|
-
return
|
|
389
|
+
// We do not call super here as this will be handled by ElementUtility to improve performance by avoiding validation and other checks.
|
|
390
|
+
return ElementUtility.insertBefore(this, newNode, referenceNode);
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
/**
|
|
@@ -6,6 +6,9 @@ import IDocument from '../document/IDocument';
|
|
|
6
6
|
import IDocumentFragment from '../document-fragment/IDocumentFragment';
|
|
7
7
|
import IHTMLElement from '../html-element/IHTMLElement';
|
|
8
8
|
import Element from './Element';
|
|
9
|
+
import NodeUtility from '../node/NodeUtility';
|
|
10
|
+
import DOMException from '../../exception/DOMException';
|
|
11
|
+
import DOMExceptionNameEnum from '../../exception/DOMExceptionNameEnum';
|
|
9
12
|
|
|
10
13
|
const NAMED_ITEM_ATTRIBUTES = ['id', 'name'];
|
|
11
14
|
|
|
@@ -16,14 +19,28 @@ export default class ElementUtility {
|
|
|
16
19
|
/**
|
|
17
20
|
* Handles appending a child element to the "children" property.
|
|
18
21
|
*
|
|
19
|
-
* @param
|
|
20
|
-
* @param node Node.
|
|
22
|
+
* @param ancestorNode Ancestor node.
|
|
23
|
+
* @param node Node to append.
|
|
24
|
+
* @param [options] Options.
|
|
25
|
+
* @param [options.disableAncestorValidation] Disables validation for checking if the node is an ancestor of the ancestorNode.
|
|
26
|
+
* @returns Appended node.
|
|
21
27
|
*/
|
|
22
28
|
public static appendChild(
|
|
23
|
-
|
|
24
|
-
node: INode
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
ancestorNode: IElement | IDocument | IDocumentFragment,
|
|
30
|
+
node: INode,
|
|
31
|
+
options?: { disableAncestorValidation?: boolean }
|
|
32
|
+
): INode {
|
|
33
|
+
if (node.nodeType === NodeTypeEnum.elementNode && node !== ancestorNode) {
|
|
34
|
+
if (
|
|
35
|
+
!options?.disableAncestorValidation &&
|
|
36
|
+
NodeUtility.isInclusiveAncestor(node, ancestorNode)
|
|
37
|
+
) {
|
|
38
|
+
throw new DOMException(
|
|
39
|
+
"Failed to execute 'appendChild' on 'Node': The new node is a parent of the node to insert to.",
|
|
40
|
+
DOMExceptionNameEnum.domException
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
if (node.parentNode && (<IHTMLElement>node.parentNode).children) {
|
|
28
45
|
const index = (<IHTMLElement>node.parentNode).children.indexOf(<IHTMLElement>node);
|
|
29
46
|
if (index !== -1) {
|
|
@@ -41,57 +58,82 @@ export default class ElementUtility {
|
|
|
41
58
|
|
|
42
59
|
for (const attribute of NAMED_ITEM_ATTRIBUTES) {
|
|
43
60
|
if ((<Element>node)._attributes[attribute]) {
|
|
44
|
-
(<HTMLCollection<IHTMLElement>>
|
|
61
|
+
(<HTMLCollection<IHTMLElement>>ancestorNode.children)._appendNamedItem(
|
|
45
62
|
<IHTMLElement>node,
|
|
46
63
|
(<Element>node)._attributes[attribute].value
|
|
47
64
|
);
|
|
48
65
|
}
|
|
49
66
|
}
|
|
50
67
|
|
|
51
|
-
|
|
68
|
+
ancestorNode.children.push(<IElement>node);
|
|
69
|
+
|
|
70
|
+
NodeUtility.appendChild(ancestorNode, node, { disableAncestorValidation: true });
|
|
71
|
+
} else {
|
|
72
|
+
NodeUtility.appendChild(ancestorNode, node, options);
|
|
52
73
|
}
|
|
74
|
+
|
|
75
|
+
return node;
|
|
53
76
|
}
|
|
54
77
|
|
|
55
78
|
/**
|
|
56
79
|
* Handles removing a child element from the "children" property.
|
|
57
80
|
*
|
|
58
|
-
* @param
|
|
81
|
+
* @param ancestorNode Ancestor node.
|
|
59
82
|
* @param node Node.
|
|
83
|
+
* @returns Removed node.
|
|
60
84
|
*/
|
|
61
85
|
public static removeChild(
|
|
62
|
-
|
|
86
|
+
ancestorNode: IElement | IDocument | IDocumentFragment,
|
|
63
87
|
node: INode
|
|
64
|
-
):
|
|
88
|
+
): INode {
|
|
65
89
|
if (node.nodeType === NodeTypeEnum.elementNode) {
|
|
66
|
-
const index =
|
|
90
|
+
const index = ancestorNode.children.indexOf(<IElement>node);
|
|
67
91
|
if (index !== -1) {
|
|
68
92
|
for (const attribute of NAMED_ITEM_ATTRIBUTES) {
|
|
69
93
|
if ((<Element>node)._attributes[attribute]) {
|
|
70
|
-
(<HTMLCollection<IHTMLElement>>
|
|
94
|
+
(<HTMLCollection<IHTMLElement>>ancestorNode.children)._removeNamedItem(
|
|
71
95
|
<IHTMLElement>node,
|
|
72
96
|
(<Element>node)._attributes[attribute].value
|
|
73
97
|
);
|
|
74
98
|
}
|
|
75
99
|
}
|
|
76
|
-
|
|
100
|
+
ancestorNode.children.splice(index, 1);
|
|
77
101
|
}
|
|
78
102
|
}
|
|
103
|
+
|
|
104
|
+
NodeUtility.removeChild(ancestorNode, node);
|
|
105
|
+
|
|
106
|
+
return node;
|
|
79
107
|
}
|
|
80
108
|
|
|
81
109
|
/**
|
|
82
110
|
*
|
|
83
111
|
* Handles inserting a child element to the "children" property.
|
|
84
112
|
*
|
|
85
|
-
* @param
|
|
86
|
-
* @param newNode
|
|
87
|
-
* @param referenceNode
|
|
113
|
+
* @param ancestorNode Ancestor node.
|
|
114
|
+
* @param newNode Node to insert.
|
|
115
|
+
* @param referenceNode Node to insert before.
|
|
116
|
+
* @param [options] Options.
|
|
117
|
+
* @param [options.disableAncestorValidation] Disables validation for checking if the node is an ancestor of the ancestorNode.
|
|
118
|
+
* @returns Inserted node.
|
|
88
119
|
*/
|
|
89
120
|
public static insertBefore(
|
|
90
|
-
|
|
121
|
+
ancestorNode: IElement | IDocument | IDocumentFragment,
|
|
91
122
|
newNode: INode,
|
|
92
|
-
referenceNode: INode | null
|
|
93
|
-
|
|
123
|
+
referenceNode: INode | null,
|
|
124
|
+
options?: { disableAncestorValidation?: boolean }
|
|
125
|
+
): INode {
|
|
94
126
|
if (newNode.nodeType === NodeTypeEnum.elementNode) {
|
|
127
|
+
if (
|
|
128
|
+
!options?.disableAncestorValidation &&
|
|
129
|
+
NodeUtility.isInclusiveAncestor(newNode, ancestorNode)
|
|
130
|
+
) {
|
|
131
|
+
throw new DOMException(
|
|
132
|
+
"Failed to execute 'insertBefore' on 'Node': The new node is a parent of the node to insert to.",
|
|
133
|
+
DOMExceptionNameEnum.domException
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
95
137
|
if (newNode.parentNode && (<IHTMLElement>newNode.parentNode).children) {
|
|
96
138
|
const index = (<IHTMLElement>newNode.parentNode).children.indexOf(<IHTMLElement>newNode);
|
|
97
139
|
if (index !== -1) {
|
|
@@ -114,19 +156,19 @@ export default class ElementUtility {
|
|
|
114
156
|
|
|
115
157
|
if (referenceNode) {
|
|
116
158
|
if (referenceNode.nodeType === NodeTypeEnum.elementNode) {
|
|
117
|
-
const index =
|
|
159
|
+
const index = ancestorNode.children.indexOf(<IElement>referenceNode);
|
|
118
160
|
if (index !== -1) {
|
|
119
|
-
|
|
161
|
+
ancestorNode.children.splice(index, 0, <IElement>newNode);
|
|
120
162
|
}
|
|
121
163
|
} else {
|
|
122
|
-
|
|
164
|
+
ancestorNode.children.length = 0;
|
|
123
165
|
|
|
124
|
-
for (const node of
|
|
166
|
+
for (const node of ancestorNode.childNodes) {
|
|
125
167
|
if (node === referenceNode) {
|
|
126
|
-
|
|
168
|
+
ancestorNode.children.push(<IElement>newNode);
|
|
127
169
|
}
|
|
128
170
|
if (node.nodeType === NodeTypeEnum.elementNode) {
|
|
129
|
-
|
|
171
|
+
ancestorNode.children.push(<IElement>node);
|
|
130
172
|
}
|
|
131
173
|
}
|
|
132
174
|
}
|
|
@@ -135,13 +177,21 @@ export default class ElementUtility {
|
|
|
135
177
|
if (referenceNode || referenceNode === null) {
|
|
136
178
|
for (const attribute of NAMED_ITEM_ATTRIBUTES) {
|
|
137
179
|
if ((<Element>newNode)._attributes[attribute]) {
|
|
138
|
-
(<HTMLCollection<IHTMLElement>>
|
|
180
|
+
(<HTMLCollection<IHTMLElement>>ancestorNode.children)._appendNamedItem(
|
|
139
181
|
<IHTMLElement>newNode,
|
|
140
182
|
(<Element>newNode)._attributes[attribute].value
|
|
141
183
|
);
|
|
142
184
|
}
|
|
143
185
|
}
|
|
144
186
|
}
|
|
187
|
+
|
|
188
|
+
NodeUtility.insertBefore(ancestorNode, newNode, referenceNode, {
|
|
189
|
+
disableAncestorValidation: true
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
NodeUtility.insertBefore(ancestorNode, newNode, referenceNode, options);
|
|
145
193
|
}
|
|
194
|
+
|
|
195
|
+
return newNode;
|
|
146
196
|
}
|
|
147
197
|
}
|
package/src/nodes/node/Node.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import EventTarget from '../../event/EventTarget';
|
|
2
|
-
import MutationRecord from '../../mutation-observer/MutationRecord';
|
|
3
|
-
import MutationTypeEnum from '../../mutation-observer/MutationTypeEnum';
|
|
4
2
|
import MutationListener from '../../mutation-observer/MutationListener';
|
|
5
3
|
import INode from './INode';
|
|
6
|
-
import DOMException from '../../exception/DOMException';
|
|
7
4
|
import IDocument from '../document/IDocument';
|
|
8
5
|
import IElement from '../element/IElement';
|
|
9
6
|
import IHTMLBaseElement from '../html-base-element/IHTMLBaseElement';
|
|
@@ -245,8 +242,8 @@ export default class Node extends EventTarget implements INode {
|
|
|
245
242
|
* @param otherNode Node to test with.
|
|
246
243
|
* @returns "true" if this node contains the other node.
|
|
247
244
|
*/
|
|
248
|
-
public contains(otherNode: INode
|
|
249
|
-
return NodeUtility.
|
|
245
|
+
public contains(otherNode: INode): boolean {
|
|
246
|
+
return NodeUtility.isInclusiveAncestor(this, otherNode);
|
|
250
247
|
}
|
|
251
248
|
|
|
252
249
|
/**
|
|
@@ -304,53 +301,7 @@ export default class Node extends EventTarget implements INode {
|
|
|
304
301
|
* @returns Appended node.
|
|
305
302
|
*/
|
|
306
303
|
public appendChild(node: INode): INode {
|
|
307
|
-
|
|
308
|
-
throw new DOMException('Not possible to append a node as a child of itself.');
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// If the type is DocumentFragment, then the child nodes of if it should be moved instead of the actual node.
|
|
312
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
|
|
313
|
-
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
314
|
-
for (const child of node.childNodes.slice()) {
|
|
315
|
-
this.appendChild(child);
|
|
316
|
-
}
|
|
317
|
-
return node;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Remove the node from its previous parent if it has any.
|
|
321
|
-
if (node.parentNode) {
|
|
322
|
-
const index = node.parentNode.childNodes.indexOf(node);
|
|
323
|
-
if (index !== -1) {
|
|
324
|
-
node.parentNode.childNodes.splice(index, 1);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (this.isConnected) {
|
|
329
|
-
(this.ownerDocument || this)['_cacheID']++;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
this.childNodes.push(node);
|
|
333
|
-
|
|
334
|
-
(<Node>node)._connectToNode(this);
|
|
335
|
-
|
|
336
|
-
// MutationObserver
|
|
337
|
-
if (this._observers.length > 0) {
|
|
338
|
-
const record = new MutationRecord();
|
|
339
|
-
record.target = this;
|
|
340
|
-
record.type = MutationTypeEnum.childList;
|
|
341
|
-
record.addedNodes = [node];
|
|
342
|
-
|
|
343
|
-
for (const observer of this._observers) {
|
|
344
|
-
if (observer.options.subtree) {
|
|
345
|
-
(<Node>node)._observe(observer);
|
|
346
|
-
}
|
|
347
|
-
if (observer.options.childList) {
|
|
348
|
-
observer.callback([record]);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return node;
|
|
304
|
+
return NodeUtility.appendChild(this, node);
|
|
354
305
|
}
|
|
355
306
|
|
|
356
307
|
/**
|
|
@@ -360,36 +311,7 @@ export default class Node extends EventTarget implements INode {
|
|
|
360
311
|
* @returns Removed node.
|
|
361
312
|
*/
|
|
362
313
|
public removeChild(node: INode): INode {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (index === -1) {
|
|
366
|
-
throw new DOMException('Failed to remove node. Node is not child of parent.');
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (this.isConnected) {
|
|
370
|
-
(this.ownerDocument || this)['_cacheID']++;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
this.childNodes.splice(index, 1);
|
|
374
|
-
|
|
375
|
-
(<Node>node)._connectToNode(null);
|
|
376
|
-
|
|
377
|
-
// MutationObserver
|
|
378
|
-
if (this._observers.length > 0) {
|
|
379
|
-
const record = new MutationRecord();
|
|
380
|
-
record.target = this;
|
|
381
|
-
record.type = MutationTypeEnum.childList;
|
|
382
|
-
record.removedNodes = [node];
|
|
383
|
-
|
|
384
|
-
for (const observer of this._observers) {
|
|
385
|
-
(<Node>node)._unobserve(observer);
|
|
386
|
-
if (observer.options.childList) {
|
|
387
|
-
observer.callback([record]);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return node;
|
|
314
|
+
return NodeUtility.removeChild(this, node);
|
|
393
315
|
}
|
|
394
316
|
|
|
395
317
|
/**
|
|
@@ -400,66 +322,7 @@ export default class Node extends EventTarget implements INode {
|
|
|
400
322
|
* @returns Inserted node.
|
|
401
323
|
*/
|
|
402
324
|
public insertBefore(newNode: INode, referenceNode: INode | null): INode {
|
|
403
|
-
|
|
404
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
|
|
405
|
-
if (newNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
406
|
-
for (const child of newNode.childNodes.slice()) {
|
|
407
|
-
this.insertBefore(child, referenceNode);
|
|
408
|
-
}
|
|
409
|
-
return newNode;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (referenceNode === null) {
|
|
413
|
-
this.appendChild(newNode);
|
|
414
|
-
return newNode;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (!referenceNode) {
|
|
418
|
-
throw new DOMException(
|
|
419
|
-
"Failed to execute 'insertBefore' on 'Node': 2 arguments required, but only 1 present.",
|
|
420
|
-
'TypeError'
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (this.childNodes.indexOf(referenceNode) === -1) {
|
|
425
|
-
throw new DOMException(
|
|
426
|
-
"Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node."
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
if (this.isConnected) {
|
|
431
|
-
(this.ownerDocument || this)['_cacheID']++;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (newNode.parentNode) {
|
|
435
|
-
const index = newNode.parentNode.childNodes.indexOf(newNode);
|
|
436
|
-
if (index !== -1) {
|
|
437
|
-
newNode.parentNode.childNodes.splice(index, 1);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
this.childNodes.splice(this.childNodes.indexOf(referenceNode), 0, newNode);
|
|
442
|
-
|
|
443
|
-
(<Node>newNode)._connectToNode(this);
|
|
444
|
-
|
|
445
|
-
// MutationObserver
|
|
446
|
-
if (this._observers.length > 0) {
|
|
447
|
-
const record = new MutationRecord();
|
|
448
|
-
record.target = this;
|
|
449
|
-
record.type = MutationTypeEnum.childList;
|
|
450
|
-
record.addedNodes = [newNode];
|
|
451
|
-
|
|
452
|
-
for (const observer of this._observers) {
|
|
453
|
-
if (observer.options.subtree) {
|
|
454
|
-
(<Node>newNode)._observe(observer);
|
|
455
|
-
}
|
|
456
|
-
if (observer.options.childList) {
|
|
457
|
-
observer.callback([record]);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
return newNode;
|
|
325
|
+
return NodeUtility.insertBefore(this, newNode, referenceNode);
|
|
463
326
|
}
|
|
464
327
|
|
|
465
328
|
/**
|