@fmdevui/fm-dev 1.0.62 → 1.0.64

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/es/component.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { FmLogin } from './packages/core/ui/login/index.mjs';
2
- import { FmTransfer, FmNoticeBar, Fmselect, FmAutocomplete, Fminputdropdown } from './packages/core/ui/components/index.mjs';
2
+ import { FmTransfer, FmNoticeBar, Fmselect, FmAutocomplete, Fminputdropdown, FmTree } from './packages/core/ui/components/index.mjs';
3
3
 
4
4
  const plugins = [
5
5
  FmLogin,
@@ -7,7 +7,8 @@ const plugins = [
7
7
  FmNoticeBar,
8
8
  Fmselect,
9
9
  FmAutocomplete,
10
- Fminputdropdown
10
+ Fminputdropdown,
11
+ FmTree
11
12
  ];
12
13
 
13
14
  export { plugins as default };
@@ -0,0 +1,90 @@
1
+ import { TreeKey } from 'element-plus/es/components/tree/src/tree.type';
2
+ import { DefineComponent, ExtractPropTypes, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
+ import { TreeKey } from 'element-plus';
4
+ declare const _default: DefineComponent<ExtractPropTypes<{
5
+ checkStrictly: {
6
+ type: BooleanConstructor;
7
+ default: boolean;
8
+ };
9
+ /**
10
+ * api service name
11
+ */
12
+ apiService: {
13
+ type: StringConstructor;
14
+ default: string;
15
+ };
16
+ /**
17
+ * api service 下的方法
18
+ */
19
+ apiAction: {
20
+ type: StringConstructor;
21
+ default: string;
22
+ };
23
+ paras: {
24
+ type: ObjectConstructor;
25
+ default: null;
26
+ };
27
+ nodeKey: {
28
+ type: StringConstructor;
29
+ default: string;
30
+ };
31
+ defaultProps: {
32
+ type: ObjectConstructor;
33
+ default: {
34
+ children: string;
35
+ label: string;
36
+ };
37
+ };
38
+ }>, {
39
+ fetchTreeData: (showLoading?: boolean) => Promise<any>;
40
+ getCheckedKeys: () => TreeKey[];
41
+ setCurrentKey: (key?: TreeKey | undefined, shouldAutoExpandParent?: boolean | undefined) => void;
42
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
43
+ "node-click": (...args: any[]) => void;
44
+ }, string, PublicProps, Readonly< ExtractPropTypes<{
45
+ checkStrictly: {
46
+ type: BooleanConstructor;
47
+ default: boolean;
48
+ };
49
+ /**
50
+ * api service name
51
+ */
52
+ apiService: {
53
+ type: StringConstructor;
54
+ default: string;
55
+ };
56
+ /**
57
+ * api service 下的方法
58
+ */
59
+ apiAction: {
60
+ type: StringConstructor;
61
+ default: string;
62
+ };
63
+ paras: {
64
+ type: ObjectConstructor;
65
+ default: null;
66
+ };
67
+ nodeKey: {
68
+ type: StringConstructor;
69
+ default: string;
70
+ };
71
+ defaultProps: {
72
+ type: ObjectConstructor;
73
+ default: {
74
+ children: string;
75
+ label: string;
76
+ };
77
+ };
78
+ }>> & Readonly<{
79
+ "onNode-click"?: ((...args: any[]) => any) | undefined;
80
+ }>, {
81
+ apiService: string;
82
+ apiAction: string;
83
+ checkStrictly: boolean;
84
+ paras: Record<string, any>;
85
+ nodeKey: string;
86
+ defaultProps: Record<string, any>;
87
+ }, {}, {}, {}, string, ComponentProvideOptions, true, {
88
+ treeRef: unknown;
89
+ }, any>;
90
+ export default _default;
@@ -1,5 +1,7 @@
1
1
  import { elSvg } from './svgIcon';
2
2
  import { DefineComponent, ExtractPropTypes, ComponentOptionsMixin, PublicProps, ComponentProvideOptions, PropType } from 'vue';
3
+ import { TreeKey } from 'element-plus';
4
+ import { TreeKey } from 'element-plus/es/components/tree/src/tree.type';
3
5
  declare const FmTransfer: DefineComponent<ExtractPropTypes<{
4
6
  leftTitle: StringConstructor;
5
7
  rightTitle: StringConstructor;
@@ -688,4 +690,78 @@ declare const Fminputdropdown: DefineComponent<ExtractPropTypes<{
688
690
  inputWidth: string;
689
691
  dropWidth: string;
690
692
  }, {}, {}, {}, string, ComponentProvideOptions, true, {}, any>;
691
- export { FmTransfer, FmNoticeBar, FmDragImg, Fmselect, FmAutocomplete, Fminputdropdown, elSvg };
693
+ declare const FmTree: DefineComponent<ExtractPropTypes<{
694
+ checkStrictly: {
695
+ type: BooleanConstructor;
696
+ default: boolean;
697
+ };
698
+ apiService: {
699
+ type: StringConstructor;
700
+ default: string;
701
+ };
702
+ apiAction: {
703
+ type: StringConstructor;
704
+ default: string;
705
+ };
706
+ paras: {
707
+ type: ObjectConstructor;
708
+ default: null;
709
+ };
710
+ nodeKey: {
711
+ type: StringConstructor;
712
+ default: string;
713
+ };
714
+ defaultProps: {
715
+ type: ObjectConstructor;
716
+ default: {
717
+ children: string;
718
+ label: string;
719
+ };
720
+ };
721
+ }>, {
722
+ fetchTreeData: (showLoading?: boolean) => Promise<any>;
723
+ getCheckedKeys: () => TreeKey[];
724
+ setCurrentKey: (key?: TreeKey | undefined, shouldAutoExpandParent?: boolean | undefined) => void;
725
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
726
+ "node-click": (...args: any[]) => void;
727
+ }, string, PublicProps, Readonly< ExtractPropTypes<{
728
+ checkStrictly: {
729
+ type: BooleanConstructor;
730
+ default: boolean;
731
+ };
732
+ apiService: {
733
+ type: StringConstructor;
734
+ default: string;
735
+ };
736
+ apiAction: {
737
+ type: StringConstructor;
738
+ default: string;
739
+ };
740
+ paras: {
741
+ type: ObjectConstructor;
742
+ default: null;
743
+ };
744
+ nodeKey: {
745
+ type: StringConstructor;
746
+ default: string;
747
+ };
748
+ defaultProps: {
749
+ type: ObjectConstructor;
750
+ default: {
751
+ children: string;
752
+ label: string;
753
+ };
754
+ };
755
+ }>> & Readonly<{
756
+ "onNode-click"?: ((...args: any[]) => any) | undefined;
757
+ }>, {
758
+ apiService: string;
759
+ apiAction: string;
760
+ checkStrictly: boolean;
761
+ paras: Record<string, any>;
762
+ nodeKey: string;
763
+ defaultProps: Record<string, any>;
764
+ }, {}, {}, {}, string, ComponentProvideOptions, true, {
765
+ treeRef: unknown;
766
+ }, any>;
767
+ export { FmTransfer, FmNoticeBar, FmDragImg, Fmselect, FmAutocomplete, Fminputdropdown, FmTree, elSvg };
package/es/index.css CHANGED
@@ -1 +1,3 @@
1
1
  .drag_verify[data-v-9e8c9ed2]{background-color:#e8e8e8;overflow:hidden;position:relative;text-align:center}.drag_verify .dv_handler[data-v-9e8c9ed2]{cursor:move;left:0;position:absolute;top:0}.drag_verify .dv_handler i[data-v-9e8c9ed2]{color:#666;font-size:16px;padding-left:0}.drag_verify .dv_handler .el-icon-circle-check[data-v-9e8c9ed2]{color:#6c6;margin-top:9px}.drag_verify .dv_progress_bar[data-v-9e8c9ed2]{height:34px;position:absolute;width:0}.drag_verify .dv_text[data-v-9e8c9ed2]{background:-webkit-gradient(linear,left top,right top,color-stop(0,var(--textColor)),color-stop(.4,var(--textColor)),color-stop(.5,#fff),color-stop(.6,var(--textColor)),color-stop(1,var(--textColor)));-webkit-background-clip:text;color:transparent;position:absolute;top:0;-moz-user-select:none;-webkit-user-select:none;user-select:none;-o-user-select:none;-ms-user-select:none;-webkit-text-fill-color:transparent;-webkit-text-size-adjust:none;animation:slidetounlock 3s infinite}.drag_verify .dv_text[data-v-9e8c9ed2] *{-webkit-text-fill-color:var(--textColor)}.goFirst[data-v-9e8c9ed2]{left:0!important;transition:left .5s}.goOrigin[data-v-9e8c9ed2]{transition:transform .5s}.goKeep[data-v-9e8c9ed2]{transition:left .2s}.goFirst2[data-v-9e8c9ed2]{transition:width .5s;width:0!important}.drag-verify-container[data-v-9e8c9ed2]{border-radius:50%;line-height:0;position:relative}.move-bar[data-v-9e8c9ed2]{position:absolute;z-index:100}.clip-bar[data-v-9e8c9ed2]{background:hsla(0,0%,100%,.8);position:absolute}.refresh[data-v-9e8c9ed2]{cursor:pointer;font-size:20px;position:absolute;right:5px;top:5px;z-index:200}.tips[data-v-9e8c9ed2]{bottom:25px;font-size:12px;height:20px;line-height:20px;position:absolute;text-align:center;width:100%;z-index:200}.tips.success[data-v-9e8c9ed2]{background:hsla(0,0%,100%,.6);color:green}.tips.danger[data-v-9e8c9ed2]{background:rgba(0,0,0,.6);color:#ff0}.check-img[data-v-9e8c9ed2]{border-radius:50%;width:100%}
2
+
3
+ .box-card[data-v-a783e82e]{flex:1}.box-card[data-v-a783e82e]>.el-card__header{padding:5px}.tree-h-flex[data-v-a783e82e]{align-items:center;display:flex}.tree-h-left[data-v-a783e82e]{flex:1;min-width:0;width:100%}.tree-h-right-group[data-v-a783e82e]{align-items:center;display:flex}
package/es/index.mjs CHANGED
@@ -3,7 +3,7 @@ export { default as emitter } from './packages/core/utils/emit/index.mjs';
3
3
  export { default as setIntroduction } from './packages/core/utils/comm/setIconfont.mjs';
4
4
  import './packages/core/index.mjs';
5
5
  export { version } from './version.mjs';
6
- export { FmAutocomplete, FmDragImg, FmNoticeBar, FmTransfer, Fminputdropdown, Fmselect } from './packages/core/ui/components/index.mjs';
6
+ export { FmAutocomplete, FmDragImg, FmNoticeBar, FmTransfer, FmTree, Fminputdropdown, Fmselect } from './packages/core/ui/components/index.mjs';
7
7
  export { elSvg } from './packages/core/ui/components/svgIcon/index.mjs';
8
8
  export { FmLogin } from './packages/core/ui/login/index.mjs';
9
9
  export { NextLoading } from './packages/core/ui/loading/index.mjs';
@@ -1,4 +1,4 @@
1
- export { FmAutocomplete, FmDragImg, FmNoticeBar, FmTransfer, Fminputdropdown, Fmselect } from './ui/components/index.mjs';
1
+ export { FmAutocomplete, FmDragImg, FmNoticeBar, FmTransfer, FmTree, Fminputdropdown, Fmselect } from './ui/components/index.mjs';
2
2
  export { FmLogin } from './ui/login/index.mjs';
3
3
  export { NextLoading } from './ui/loading/index.mjs';
4
4
  export { AccountTypeEnum, HttpMethodEnum, JobCreateTypeEnum } from './api/index.mjs';
@@ -0,0 +1,7 @@
1
+ import _sfc_main from './index.vue2.mjs';
2
+ import './index.vue3.mjs';
3
+ import _export_sfc from '../../../../../_virtual/_plugin-vue_export-helper.mjs';
4
+
5
+ var fmtree = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a783e82e"]]);
6
+
7
+ export { fmtree as default };
@@ -0,0 +1,241 @@
1
+ import { defineComponent, ref, reactive, onMounted, watch, resolveComponent, resolveDirective, createBlock, openBlock, withCtx, withDirectives, createElementBlock, createVNode, createCommentVNode, createTextVNode, toDisplayString, createElementVNode, unref } from 'vue';
2
+ import { Search, MoreFilled } from '@element-plus/icons-vue';
3
+ import { useBaseApi } from '../../../api/base/index.mjs';
4
+
5
+ const _hoisted_1 = { class: "card-header" };
6
+ const _hoisted_2 = { class: "tree-h-flex" };
7
+ const _hoisted_3 = { class: "tree-h-left" };
8
+ const _hoisted_4 = { class: "tree-h-right-group" };
9
+ const _hoisted_5 = { style: { "margin-bottom": "45px" } };
10
+ var _sfc_main = /* @__PURE__ */ defineComponent({
11
+ ...{
12
+ name: "FmTree"
13
+ },
14
+ __name: "index",
15
+ props: {
16
+ checkStrictly: { type: Boolean, default: true },
17
+ /**
18
+ * api service name
19
+ */
20
+ apiService: {
21
+ type: String,
22
+ default: "planOrder"
23
+ },
24
+ /**
25
+ * api service 下的方法
26
+ */
27
+ apiAction: {
28
+ type: String,
29
+ default: "autoQuerySearch"
30
+ },
31
+ paras: {
32
+ type: Object,
33
+ default: null
34
+ },
35
+ nodeKey: {
36
+ type: String,
37
+ default: "id"
38
+ },
39
+ defaultProps: {
40
+ type: Object,
41
+ default: { children: "children", label: "name" }
42
+ }
43
+ },
44
+ emits: ["node-click"],
45
+ setup(__props, { expose: __expose, emit: __emit }) {
46
+ const props = __props;
47
+ const filterText = ref("");
48
+ const treeRef = ref();
49
+ const state = reactive({
50
+ loading: false,
51
+ folderData: [],
52
+ isShowCheckbox: false,
53
+ strictly: false
54
+ });
55
+ onMounted(async () => {
56
+ await fetchTreeData();
57
+ });
58
+ watch(filterText, (val) => {
59
+ treeRef.value.filter(val);
60
+ });
61
+ const fetchTreeData = async (showLoading = true) => {
62
+ if (showLoading) state.loading = true;
63
+ var res = await useBaseApi(props.apiService).get(props.paras, props.apiAction);
64
+ state.folderData = res.data.result ?? [];
65
+ if (showLoading) state.loading = false;
66
+ return res.data.result ?? [];
67
+ };
68
+ const getCheckedKeys = () => {
69
+ return treeRef.value.getCheckedKeys();
70
+ };
71
+ const filterNode = (value, data) => {
72
+ if (!value) return true;
73
+ return data.name.includes(value);
74
+ };
75
+ const handleCommand = async (command) => {
76
+ if ("expandAll" == command) {
77
+ for (let i = 0; i < treeRef.value.store._getAllNodes().length; i++) {
78
+ treeRef.value.store._getAllNodes()[i].expanded = true;
79
+ }
80
+ } else if ("collapseAll" == command) {
81
+ for (let i = 0; i < treeRef.value.store._getAllNodes().length; i++) {
82
+ treeRef.value.store._getAllNodes()[i].expanded = false;
83
+ }
84
+ } else if ("refresh" == command) {
85
+ fetchTreeData();
86
+ } else if ("rootNode" == command) {
87
+ treeRef.value?.setCurrentKey();
88
+ emit("node-click", { id: 0, name: "" });
89
+ }
90
+ };
91
+ const emit = __emit;
92
+ const nodeClick = (node) => {
93
+ emit("node-click", { id: node.id, name: node.name });
94
+ };
95
+ const setCurrentKey = (key, shouldAutoExpandParent) => {
96
+ treeRef.value?.setCurrentKey(key, shouldAutoExpandParent);
97
+ };
98
+ __expose({ fetchTreeData, getCheckedKeys, setCurrentKey });
99
+ return (_ctx, _cache) => {
100
+ const _component_el_input = resolveComponent("el-input");
101
+ const _component_el_icon = resolveComponent("el-icon");
102
+ const _component_el_button = resolveComponent("el-button");
103
+ const _component_el_dropdown_item = resolveComponent("el-dropdown-item");
104
+ const _component_el_dropdown_menu = resolveComponent("el-dropdown-menu");
105
+ const _component_el_dropdown = resolveComponent("el-dropdown");
106
+ const _component_el_checkbox = resolveComponent("el-checkbox");
107
+ const _component_el_tree = resolveComponent("el-tree");
108
+ const _component_el_scrollbar = resolveComponent("el-scrollbar");
109
+ const _component_el_card = resolveComponent("el-card");
110
+ const _directive_loading = resolveDirective("loading");
111
+ return openBlock(), createBlock(_component_el_card, {
112
+ class: "box-card",
113
+ shadow: "hover",
114
+ "body-style": "height:100%;overflow:auto;padding:5px;width:100%;"
115
+ }, {
116
+ header: withCtx(() => [
117
+ createElementVNode("div", _hoisted_1, [
118
+ createElementVNode("div", _hoisted_2, [
119
+ createElementVNode("div", _hoisted_3, [
120
+ createVNode(_component_el_input, {
121
+ "prefix-icon": unref(Search),
122
+ modelValue: filterText.value,
123
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => filterText.value = $event),
124
+ modelModifiers: { lazy: true },
125
+ clearable: "",
126
+ placeholder: "\u7C7B\u578B\u540D\u79F0"
127
+ }, null, 8, ["prefix-icon", "modelValue"])
128
+ ]),
129
+ createElementVNode("div", _hoisted_4, [
130
+ createVNode(_component_el_dropdown, { onCommand: handleCommand }, {
131
+ dropdown: withCtx(() => [
132
+ createVNode(_component_el_dropdown_menu, null, {
133
+ default: withCtx(() => [
134
+ createVNode(_component_el_dropdown_item, { command: "expandAll" }, {
135
+ default: withCtx(() => _cache[2] || (_cache[2] = [
136
+ createTextVNode("\u5168\u90E8\u5C55\u5F00")
137
+ ])),
138
+ _: 1,
139
+ __: [2]
140
+ }),
141
+ createVNode(_component_el_dropdown_item, { command: "collapseAll" }, {
142
+ default: withCtx(() => _cache[3] || (_cache[3] = [
143
+ createTextVNode("\u5168\u90E8\u6298\u53E0")
144
+ ])),
145
+ _: 1,
146
+ __: [3]
147
+ }),
148
+ createVNode(_component_el_dropdown_item, { command: "rootNode" }, {
149
+ default: withCtx(() => _cache[4] || (_cache[4] = [
150
+ createTextVNode("\u6839\u8282\u70B9")
151
+ ])),
152
+ _: 1,
153
+ __: [4]
154
+ }),
155
+ createVNode(_component_el_dropdown_item, { command: "refresh" }, {
156
+ default: withCtx(() => _cache[5] || (_cache[5] = [
157
+ createTextVNode("\u5237\u65B0")
158
+ ])),
159
+ _: 1,
160
+ __: [5]
161
+ })
162
+ ]),
163
+ _: 1
164
+ /* STABLE */
165
+ })
166
+ ]),
167
+ default: withCtx(() => [
168
+ createVNode(_component_el_button, { style: { "margin-left": "8px", "width": "34px" } }, {
169
+ default: withCtx(() => [
170
+ createVNode(_component_el_icon, { class: "el-icon--center" }, {
171
+ default: withCtx(() => [
172
+ createVNode(unref(MoreFilled))
173
+ ]),
174
+ _: 1
175
+ /* STABLE */
176
+ })
177
+ ]),
178
+ _: 1
179
+ /* STABLE */
180
+ })
181
+ ]),
182
+ _: 1
183
+ /* STABLE */
184
+ })
185
+ ]),
186
+ !props.checkStrictly && state.isShowCheckbox ? (openBlock(), createBlock(_component_el_checkbox, {
187
+ key: 0,
188
+ modelValue: state.strictly,
189
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => state.strictly = $event),
190
+ label: "\u8054\u52A8",
191
+ style: { "margin-left": "8px" },
192
+ border: ""
193
+ }, null, 8, ["modelValue"])) : createCommentVNode("v-if", true)
194
+ ])
195
+ ])
196
+ ]),
197
+ default: withCtx(() => [
198
+ withDirectives((openBlock(), createElementBlock("div", _hoisted_5, [
199
+ createVNode(_component_el_scrollbar, null, {
200
+ default: withCtx(() => [
201
+ createVNode(_component_el_tree, {
202
+ ref_key: "treeRef",
203
+ ref: treeRef,
204
+ class: "filter-tree",
205
+ data: state.folderData,
206
+ "node-key": __props.nodeKey,
207
+ props: __props.defaultProps,
208
+ "filter-node-method": filterNode,
209
+ onNodeClick: nodeClick,
210
+ "show-checkbox": state.isShowCheckbox,
211
+ "default-expand-all": "",
212
+ "highlight-current": "",
213
+ "check-strictly": !state.strictly
214
+ }, {
215
+ default: withCtx(({ node }) => [
216
+ createCommentVNode(' <el-icon v-if="node.level < 4" size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-FolderOpened /></el-icon>\r\n <el-icon v-else size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Folder /></el-icon> '),
217
+ createTextVNode(
218
+ " " + toDisplayString(node.label),
219
+ 1
220
+ /* TEXT */
221
+ )
222
+ ]),
223
+ _: 1
224
+ /* STABLE */
225
+ }, 8, ["data", "node-key", "props", "show-checkbox", "check-strictly"])
226
+ ]),
227
+ _: 1
228
+ /* STABLE */
229
+ })
230
+ ])), [
231
+ [_directive_loading, state.loading]
232
+ ])
233
+ ]),
234
+ _: 1
235
+ /* STABLE */
236
+ });
237
+ };
238
+ }
239
+ });
240
+
241
+ export { _sfc_main as default };
@@ -0,0 +1,3 @@
1
+ var undefined$1 = undefined;
2
+
3
+ export { undefined$1 as default };
@@ -4,6 +4,7 @@ import dragimg from './dragVerify/dragVerifyImgRotate.vue.mjs';
4
4
  import './fmselect/index.vue.mjs';
5
5
  import './fmautocomplete/index.vue.mjs';
6
6
  import './inputdropdown/index.vue.mjs';
7
+ import fmtree from './fmtree/index.vue.mjs';
7
8
  export { elSvg } from './svgIcon/index.mjs';
8
9
  import _sfc_main from './transfer/index.vue2.mjs';
9
10
  import _sfc_main$1 from './noticeBar/index.vue2.mjs';
@@ -17,5 +18,6 @@ const FmDragImg = dragimg;
17
18
  const Fmselect = _sfc_main$2;
18
19
  const FmAutocomplete = _sfc_main$3;
19
20
  const Fminputdropdown = _sfc_main$4;
21
+ const FmTree = fmtree;
20
22
 
21
- export { FmAutocomplete, FmDragImg, FmNoticeBar, FmTransfer, Fminputdropdown, Fmselect };
23
+ export { FmAutocomplete, FmDragImg, FmNoticeBar, FmTransfer, FmTree, Fminputdropdown, Fmselect };
package/index.css CHANGED
@@ -111,3 +111,30 @@
111
111
  }
112
112
 
113
113
 
114
+
115
+
116
+ .box-card[data-v-a783e82e] {
117
+ flex: 1;
118
+ }
119
+ .box-card[data-v-a783e82e]> .el-card__header {
120
+ padding: 5px;
121
+ }
122
+ .tree-h-flex[data-v-a783e82e] {
123
+ display: flex;
124
+ align-items: center; /* 纵向居中 */
125
+ }
126
+ .tree-h-left[data-v-a783e82e] {
127
+ flex: 1;
128
+ min-width: 0; /* 防止内容溢出 */
129
+ width: 100%;
130
+ }
131
+ .tree-h-right-group[data-v-a783e82e] {
132
+ display: flex;
133
+ align-items: center;
134
+ }
135
+
136
+
137
+ /* .tree-h-right {
138
+ width: 42px;
139
+ min-width: 42px;
140
+ } */