jodit 4.12.44 → 4.13.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/es2015/jodit.css +6 -1
  3. package/es2015/jodit.fat.min.css +1 -1
  4. package/es2015/jodit.fat.min.js +14 -14
  5. package/es2015/jodit.js +156 -17
  6. package/es2015/jodit.min.css +1 -1
  7. package/es2015/jodit.min.js +5 -5
  8. package/es2015/plugins/debug/debug.css +1 -1
  9. package/es2015/plugins/debug/debug.js +1 -1
  10. package/es2015/plugins/debug/debug.min.js +1 -1
  11. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  12. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  13. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  14. package/es2018/jodit.fat.min.css +1 -1
  15. package/es2018/jodit.fat.min.js +3 -3
  16. package/es2018/jodit.min.css +1 -1
  17. package/es2018/jodit.min.js +5 -5
  18. package/es2018/plugins/debug/debug.min.js +1 -1
  19. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  20. package/es2021/jodit.css +6 -1
  21. package/es2021/jodit.fat.min.css +1 -1
  22. package/es2021/jodit.fat.min.js +4 -4
  23. package/es2021/jodit.js +147 -17
  24. package/es2021/jodit.min.css +1 -1
  25. package/es2021/jodit.min.js +6 -6
  26. package/es2021/plugins/debug/debug.css +1 -1
  27. package/es2021/plugins/debug/debug.js +1 -1
  28. package/es2021/plugins/debug/debug.min.js +1 -1
  29. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  30. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  31. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  32. package/es2021.en/jodit.css +6 -1
  33. package/es2021.en/jodit.fat.min.css +1 -1
  34. package/es2021.en/jodit.fat.min.js +5 -5
  35. package/es2021.en/jodit.js +147 -17
  36. package/es2021.en/jodit.min.css +1 -1
  37. package/es2021.en/jodit.min.js +5 -5
  38. package/es2021.en/plugins/debug/debug.css +1 -1
  39. package/es2021.en/plugins/debug/debug.js +1 -1
  40. package/es2021.en/plugins/debug/debug.min.js +1 -1
  41. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  42. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  43. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  44. package/es5/jodit.css +7 -2
  45. package/es5/jodit.fat.min.css +1 -1
  46. package/es5/jodit.fat.min.js +2 -2
  47. package/es5/jodit.js +192 -17
  48. package/es5/jodit.min.css +3 -3
  49. package/es5/jodit.min.js +2 -2
  50. package/es5/plugins/debug/debug.css +1 -1
  51. package/es5/plugins/debug/debug.js +1 -1
  52. package/es5/plugins/debug/debug.min.js +1 -1
  53. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  54. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  55. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  56. package/es5/polyfills.fat.min.js +1 -1
  57. package/es5/polyfills.js +1 -1
  58. package/es5/polyfills.min.js +1 -1
  59. package/esm/core/constants.js +1 -1
  60. package/esm/core/selection/selection.d.ts +31 -0
  61. package/esm/core/selection/selection.js +143 -14
  62. package/esm/core/view/view-with-toolbar.d.ts +6 -0
  63. package/esm/core/view/view-with-toolbar.js +18 -2
  64. package/esm/jodit.js +7 -0
  65. package/esm/types/jodit.d.ts +2 -0
  66. package/package.json +1 -1
  67. package/types/core/selection/selection.d.ts +31 -0
  68. package/types/core/view/view-with-toolbar.d.ts +6 -0
  69. package/types/types/jodit.d.ts +2 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
package/es5/polyfills.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.44
4
+ * Version: v4.13.3
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -3,7 +3,7 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
- export const APP_VERSION = "4.12.44";
6
+ export const APP_VERSION = "4.13.3";
7
7
  // prettier-ignore
8
8
  export const ES = "es2020";
9
9
  export const IS_ES_MODERN = true;
@@ -224,6 +224,37 @@ export declare class Selection implements ISelect {
224
224
  * ```
225
225
  */
226
226
  get html(): string;
227
+ /**
228
+ * Splits the boundaries of the current selection and wraps every
229
+ * contiguous run of selected inline content (grouped by block) into a
230
+ * `<font>` element, returning those wrappers in document order.
231
+ *
232
+ * This is a pure-DOM replacement for the old
233
+ * `nativeExecCommand('fontsize', false, '7')` trick which relied on the
234
+ * browser to split the selection into `<font size="7">` fragments.
235
+ */
236
+ private __wrapSelectionFragments;
237
+ /**
238
+ * Splits the text nodes at both ends of the range so that its boundaries
239
+ * always fall between nodes. Afterwards every node inside the range is
240
+ * fully (not partially) selected.
241
+ */
242
+ private __splitSelectionBoundaries;
243
+ private __normalizeRangeBoundary;
244
+ /**
245
+ * Collects the highest-level nodes that are completely inside the range,
246
+ * descending into nodes that are only partially selected.
247
+ */
248
+ private __collectContainedNodes;
249
+ private __isFullyContained;
250
+ /**
251
+ * Wraps every contiguous run of selected inline siblings into a `<font>`
252
+ * element. Block-level nodes are never wrapped themselves - their inline
253
+ * content is wrapped instead, keeping every `<font>` inside a single block.
254
+ */
255
+ private __wrapSelectionRuns;
256
+ private __isOrContainsBlock;
257
+ private __wrapRunInFont;
227
258
  /**
228
259
  * Wrap all selected fragments inside Tag or apply some callback
229
260
  */
@@ -898,6 +898,148 @@ export class Selection {
898
898
  }
899
899
  return '';
900
900
  }
901
+ /**
902
+ * Splits the boundaries of the current selection and wraps every
903
+ * contiguous run of selected inline content (grouped by block) into a
904
+ * `<font>` element, returning those wrappers in document order.
905
+ *
906
+ * This is a pure-DOM replacement for the old
907
+ * `nativeExecCommand('fontsize', false, '7')` trick which relied on the
908
+ * browser to split the selection into `<font size="7">` fragments.
909
+ */
910
+ __wrapSelectionFragments() {
911
+ const range = this.range;
912
+ this.__splitSelectionBoundaries(range);
913
+ let root = range.commonAncestorContainer;
914
+ if (Dom.isText(root)) {
915
+ root = root.parentNode;
916
+ }
917
+ if (!root) {
918
+ return [];
919
+ }
920
+ return this.__wrapSelectionRuns(this.__collectContainedNodes(root, range));
921
+ }
922
+ /**
923
+ * Splits the text nodes at both ends of the range so that its boundaries
924
+ * always fall between nodes. Afterwards every node inside the range is
925
+ * fully (not partially) selected.
926
+ */
927
+ __splitSelectionBoundaries(range) {
928
+ var _a, _b, _c, _d, _e, _f, _g, _h;
929
+ let { startContainer, endContainer } = range;
930
+ let { startOffset, endOffset } = range;
931
+ if (Dom.isText(endContainer) &&
932
+ endOffset > 0 &&
933
+ endOffset < ((_b = (_a = endContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0)) {
934
+ endContainer.splitText(endOffset);
935
+ endOffset = (_d = (_c = endContainer.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : endOffset;
936
+ }
937
+ if (Dom.isText(startContainer) &&
938
+ startOffset > 0 &&
939
+ startOffset < ((_f = (_e = startContainer.nodeValue) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0)) {
940
+ const middle = startContainer.splitText(startOffset);
941
+ // Selection located inside a single text node - the tail we just
942
+ // cut off is the actual selected fragment.
943
+ if (startContainer === endContainer) {
944
+ endContainer = middle;
945
+ endOffset = (_h = (_g = middle.nodeValue) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0;
946
+ }
947
+ startContainer = middle;
948
+ startOffset = 0;
949
+ }
950
+ range.setStart(startContainer, startOffset);
951
+ range.setEnd(endContainer, endOffset);
952
+ // Normalize text-edge boundaries (e.g. `(text, 0)` or `(text, length)`)
953
+ // to the element level so that containment checks based on
954
+ // `selectNode()` treat a fully selected text node as contained.
955
+ this.__normalizeRangeBoundary(range, true);
956
+ this.__normalizeRangeBoundary(range, false);
957
+ }
958
+ __normalizeRangeBoundary(range, atStart) {
959
+ var _a, _b;
960
+ const container = atStart ? range.startContainer : range.endContainer;
961
+ if (!Dom.isText(container)) {
962
+ return;
963
+ }
964
+ const offset = atStart ? range.startOffset : range.endOffset;
965
+ const length = (_b = (_a = container.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
966
+ if (offset === 0) {
967
+ atStart
968
+ ? range.setStartBefore(container)
969
+ : range.setEndBefore(container);
970
+ }
971
+ else if (offset >= length) {
972
+ atStart
973
+ ? range.setStartAfter(container)
974
+ : range.setEndAfter(container);
975
+ }
976
+ }
977
+ /**
978
+ * Collects the highest-level nodes that are completely inside the range,
979
+ * descending into nodes that are only partially selected.
980
+ */
981
+ __collectContainedNodes(root, range) {
982
+ const result = [];
983
+ toArray(root.childNodes).forEach(child => {
984
+ if (this.__isFullyContained(range, child)) {
985
+ result.push(child);
986
+ }
987
+ else if (child.childNodes.length && range.intersectsNode(child)) {
988
+ result.push(...this.__collectContainedNodes(child, range));
989
+ }
990
+ });
991
+ return result;
992
+ }
993
+ __isFullyContained(range, node) {
994
+ const nodeRange = this.createRange();
995
+ nodeRange.selectNode(node);
996
+ return (range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
997
+ range.compareBoundaryPoints(Range.END_TO_END, nodeRange) >= 0);
998
+ }
999
+ /**
1000
+ * Wraps every contiguous run of selected inline siblings into a `<font>`
1001
+ * element. Block-level nodes are never wrapped themselves - their inline
1002
+ * content is wrapped instead, keeping every `<font>` inside a single block.
1003
+ */
1004
+ __wrapSelectionRuns(nodes) {
1005
+ const fonts = [];
1006
+ let run = [];
1007
+ const flush = () => {
1008
+ if (run.length) {
1009
+ fonts.push(this.__wrapRunInFont(run));
1010
+ run = [];
1011
+ }
1012
+ };
1013
+ nodes.forEach(node => {
1014
+ if (Dom.isElement(node) && this.__isOrContainsBlock(node)) {
1015
+ flush();
1016
+ fonts.push(...this.__wrapSelectionRuns(toArray(node.childNodes)));
1017
+ }
1018
+ else {
1019
+ if (run.length &&
1020
+ run[run.length - 1].parentNode !== node.parentNode) {
1021
+ flush();
1022
+ }
1023
+ run.push(node);
1024
+ }
1025
+ });
1026
+ flush();
1027
+ return fonts;
1028
+ }
1029
+ __isOrContainsBlock(node) {
1030
+ if (Dom.isBlock(node)) {
1031
+ return true;
1032
+ }
1033
+ return toArray(node.childNodes).some(child => this.__isOrContainsBlock(child));
1034
+ }
1035
+ __wrapRunInFont(run) {
1036
+ var _a;
1037
+ const font = this.j.createInside.element('font');
1038
+ const [first] = run;
1039
+ (_a = first.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(font, first);
1040
+ run.forEach(node => font.appendChild(node));
1041
+ return font;
1042
+ }
901
1043
  /**
902
1044
  * Wrap all selected fragments inside Tag or apply some callback
903
1045
  */
@@ -912,20 +1054,7 @@ export class Selection {
912
1054
  Dom.unwrap(font);
913
1055
  return;
914
1056
  }
915
- // fix issue https://github.com/xdan/jodit/issues/65
916
- $$('*[style*=font-size]', this.area).forEach(elm => {
917
- attr(elm, 'data-font-size', elm.style.fontSize.toString());
918
- elm.style.removeProperty('font-size');
919
- });
920
- this.j.nativeExecCommand('fontsize', false, '7');
921
- $$('*[data-font-size]', this.area).forEach(elm => {
922
- const fontSize = attr(elm, 'data-font-size');
923
- if (fontSize) {
924
- elm.style.fontSize = fontSize;
925
- attr(elm, 'data-font-size', null);
926
- }
927
- });
928
- const elms = $$('font[size="7"]', this.area);
1057
+ const elms = this.__wrapSelectionFragments();
929
1058
  for (const font of elms) {
930
1059
  const { firstChild, lastChild } = font;
931
1060
  if (firstChild &&
@@ -16,6 +16,12 @@ export declare abstract class ViewWithToolbar extends View implements IViewWithT
16
16
  * Container for toolbar
17
17
  */
18
18
  get toolbarContainer(): HTMLElement;
19
+ /**
20
+ * Keep the toolbar box as the first child of the container, except that
21
+ * children flagged with `data-jodit-above-toolbar` (e.g. the `above`
22
+ * workplace slot used for presence bars and banners) stay above it.
23
+ */
24
+ private __appendToolbarBox;
19
25
  /**
20
26
  * Change panel container
21
27
  */
@@ -33,10 +33,26 @@ export class ViewWithToolbar extends View {
33
33
  (isString(this.o.toolbar) || Dom.isHTMLElement(this.o.toolbar))) {
34
34
  return resolveElement(this.o.toolbar, this.o.shadowRoot || this.od);
35
35
  }
36
- this.o.toolbar &&
37
- Dom.appendChildFirst(this.container, this.__defaultToolbarContainer);
36
+ this.o.toolbar && this.__appendToolbarBox();
38
37
  return this.__defaultToolbarContainer;
39
38
  }
39
+ /**
40
+ * Keep the toolbar box as the first child of the container, except that
41
+ * children flagged with `data-jodit-above-toolbar` (e.g. the `above`
42
+ * workplace slot used for presence bars and banners) stay above it.
43
+ */
44
+ __appendToolbarBox() {
45
+ const box = this.__defaultToolbarContainer;
46
+ let anchor = this.container.firstElementChild;
47
+ while (anchor &&
48
+ anchor !== box &&
49
+ anchor.hasAttribute('data-jodit-above-toolbar')) {
50
+ anchor = anchor.nextElementSibling;
51
+ }
52
+ if (anchor !== box) {
53
+ this.container.insertBefore(box, anchor);
54
+ }
55
+ }
40
56
  /**
41
57
  * Change panel container
42
58
  */
package/esm/jodit.js CHANGED
@@ -1016,6 +1016,12 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1016
1016
  element.style.display = 'none';
1017
1017
  }
1018
1018
  const SLOT = 'workplace-slot';
1019
+ // A slot that always stays ABOVE the toolbar (presence bars, banners…).
1020
+ // The `data-jodit-above-toolbar` attribute tells ViewWithToolbar to keep
1021
+ // the toolbar box below it when (re)attaching the toolbar container.
1022
+ const aboveSlot = this.c.div(this.getFullElName(SLOT, 'above'), NOEDIT);
1023
+ aboveSlot.setAttribute('data-jodit-above-toolbar', '');
1024
+ Dom.appendChildFirst(container, aboveSlot);
1019
1025
  const topSlot = this.c.div(this.getFullElName(SLOT, 'top'), NOEDIT);
1020
1026
  container.appendChild(topSlot);
1021
1027
  const centerSlot = this.c.div(this.getFullElName(SLOT, 'center'), NOEDIT);
@@ -1048,6 +1054,7 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1048
1054
  container,
1049
1055
  workplace,
1050
1056
  slots: {
1057
+ above: aboveSlot,
1051
1058
  top: topSlot,
1052
1059
  bottom: bottomPanel,
1053
1060
  center: centerSlot,
@@ -18,6 +18,8 @@ interface IWorkPlace {
18
18
  container: HTMLDivElement;
19
19
  workplace: HTMLDivElement;
20
20
  slots: {
21
+ /** Sits above the toolbar (presence bars, banners). */
22
+ above: HTMLDivElement;
21
23
  top: HTMLDivElement;
22
24
  bottom: HTMLDivElement;
23
25
  center: HTMLDivElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "4.12.44",
3
+ "version": "4.13.3",
4
4
  "description": "Jodit is an awesome and useful wysiwyg editor with filebrowser",
5
5
  "main": "esm/index.js",
6
6
  "types": "types/index.d.ts",
@@ -224,6 +224,37 @@ export declare class Selection implements ISelect {
224
224
  * ```
225
225
  */
226
226
  get html(): string;
227
+ /**
228
+ * Splits the boundaries of the current selection and wraps every
229
+ * contiguous run of selected inline content (grouped by block) into a
230
+ * `<font>` element, returning those wrappers in document order.
231
+ *
232
+ * This is a pure-DOM replacement for the old
233
+ * `nativeExecCommand('fontsize', false, '7')` trick which relied on the
234
+ * browser to split the selection into `<font size="7">` fragments.
235
+ */
236
+ private __wrapSelectionFragments;
237
+ /**
238
+ * Splits the text nodes at both ends of the range so that its boundaries
239
+ * always fall between nodes. Afterwards every node inside the range is
240
+ * fully (not partially) selected.
241
+ */
242
+ private __splitSelectionBoundaries;
243
+ private __normalizeRangeBoundary;
244
+ /**
245
+ * Collects the highest-level nodes that are completely inside the range,
246
+ * descending into nodes that are only partially selected.
247
+ */
248
+ private __collectContainedNodes;
249
+ private __isFullyContained;
250
+ /**
251
+ * Wraps every contiguous run of selected inline siblings into a `<font>`
252
+ * element. Block-level nodes are never wrapped themselves - their inline
253
+ * content is wrapped instead, keeping every `<font>` inside a single block.
254
+ */
255
+ private __wrapSelectionRuns;
256
+ private __isOrContainsBlock;
257
+ private __wrapRunInFont;
227
258
  /**
228
259
  * Wrap all selected fragments inside Tag or apply some callback
229
260
  */
@@ -16,6 +16,12 @@ export declare abstract class ViewWithToolbar extends View implements IViewWithT
16
16
  * Container for toolbar
17
17
  */
18
18
  get toolbarContainer(): HTMLElement;
19
+ /**
20
+ * Keep the toolbar box as the first child of the container, except that
21
+ * children flagged with `data-jodit-above-toolbar` (e.g. the `above`
22
+ * workplace slot used for presence bars and banners) stay above it.
23
+ */
24
+ private __appendToolbarBox;
19
25
  /**
20
26
  * Change panel container
21
27
  */
@@ -18,6 +18,8 @@ interface IWorkPlace {
18
18
  container: HTMLDivElement;
19
19
  workplace: HTMLDivElement;
20
20
  slots: {
21
+ /** Sits above the toolbar (presence bars, banners). */
22
+ above: HTMLDivElement;
21
23
  top: HTMLDivElement;
22
24
  bottom: HTMLDivElement;
23
25
  center: HTMLDivElement;