@v1nt1248/3nclient-lib 0.3.19 → 0.3.20
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 +1 -0
- package/dist/components/ui3n-button/constants.d.ts +5 -0
- package/dist/components/ui3n-button/types.d.ts +4 -2
- package/dist/components/ui3n-button/ui3n-button.vue.d.ts +2 -2
- package/dist/components/ui3n-input/types.d.ts +5 -0
- package/dist/components/ui3n-input/ui3n-input.vue.d.ts +18 -1
- package/dist/style.css +1 -1
- package/dist/ui3n-components.js +6233 -3165
- package/dist/ui3n-plugins.js +1831 -1170
- package/dist/ui3n-utils.js +1751 -1089
- package/dist/utils/debounce.d.ts +8 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/variables.css +1 -0
- package/package.json +23 -22
- package/src/components/ui3n-autocomplete/ui3n-autocomplete.vue +1 -0
- package/src/components/ui3n-button/constants.ts +5 -0
- package/src/components/ui3n-button/types.ts +4 -2
- package/src/components/ui3n-button/ui3n-button.vue +378 -90
- package/src/components/ui3n-input/types.ts +5 -0
- package/src/components/ui3n-input/ui3n-input.vue +177 -96
|
@@ -1,49 +1,106 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed, onMounted, ref, watch } from 'vue';
|
|
2
|
+
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
|
3
3
|
import Ui3nIcon from '../ui3n-icon/ui3n-icon.vue';
|
|
4
4
|
import Ui3nButton from '../ui3n-button/ui3n-button.vue';
|
|
5
5
|
import type { Ui3nInputEmits, Ui3nInputProps } from './types';
|
|
6
6
|
|
|
7
|
-
const props = defineProps<Ui3nInputProps>()
|
|
7
|
+
const props = withDefaults(defineProps<Ui3nInputProps>(), {
|
|
8
|
+
modelValue: '',
|
|
9
|
+
type: 'text',
|
|
10
|
+
size: 'regular',
|
|
11
|
+
label: '',
|
|
12
|
+
placeholder: '',
|
|
13
|
+
icon: '',
|
|
14
|
+
iconColor: '',
|
|
15
|
+
displayStateMode: undefined,
|
|
16
|
+
displayStateMessage: '',
|
|
17
|
+
rules: () => [],
|
|
18
|
+
clearable: false,
|
|
19
|
+
autofocus: false,
|
|
20
|
+
validateAtStartup: false,
|
|
21
|
+
hideBottomSpace: false,
|
|
22
|
+
displayStateWithIcon: false,
|
|
23
|
+
disabled: false,
|
|
24
|
+
});
|
|
8
25
|
const emits = defineEmits<Ui3nInputEmits>();
|
|
9
26
|
|
|
10
27
|
const inputElement = ref<HTMLInputElement | null>(null);
|
|
11
|
-
const
|
|
28
|
+
const internalValue = ref('');
|
|
12
29
|
const isDirty = ref(false);
|
|
13
30
|
const isFocused = ref(false);
|
|
14
31
|
const errorMessage = ref('');
|
|
15
32
|
|
|
16
|
-
const isInitialized = ref(false);
|
|
17
|
-
|
|
18
33
|
const cssIconColor = computed(() => {
|
|
19
34
|
if (props.disabled) {
|
|
20
35
|
return 'var(--color-icon-control-primary-disabled)';
|
|
21
36
|
}
|
|
22
|
-
|
|
23
37
|
return props.iconColor || 'var(--color-icon-control-primary-default)';
|
|
24
38
|
});
|
|
25
39
|
|
|
40
|
+
const showSuccessIcon = computed(
|
|
41
|
+
() => props.displayStateMode === 'success' && props.displayStateWithIcon && !isFocused.value,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const showClearButton = computed(
|
|
45
|
+
() => !props.disabled && props.clearable && !!internalValue.value && !showSuccessIcon.value,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const showMessageBlock = computed(
|
|
49
|
+
() => !!errorMessage.value || !!(props.displayStateMode && props.displayStateMessage),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const isErrorMessage = computed(
|
|
53
|
+
() => !!errorMessage.value || (props.displayStateMode === 'error' && !!props.displayStateMessage),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const isSuccessMessage = computed(() => props.displayStateMode === 'success' && !!props.displayStateMessage);
|
|
57
|
+
|
|
58
|
+
function getTargetValue(event: Event | KeyboardEvent): string {
|
|
59
|
+
return (event.target as HTMLInputElement).value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function validate(value: string) {
|
|
63
|
+
const errors: string[] = [];
|
|
64
|
+
for (const rule of props.rules) {
|
|
65
|
+
if (typeof rule !== 'function') {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const result = rule(value);
|
|
70
|
+
if (typeof result === 'string') {
|
|
71
|
+
errors.push(result);
|
|
72
|
+
} else if (!result) {
|
|
73
|
+
errors.push('Invalid');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
errorMessage.value = errors.join('. ');
|
|
78
|
+
if (isDirty.value || props.validateAtStartup) {
|
|
79
|
+
emits('update:valid', errors.length === 0);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
26
83
|
function onFocus(event: Event) {
|
|
27
84
|
isFocused.value = true;
|
|
28
85
|
emits('focus', event);
|
|
29
86
|
}
|
|
30
87
|
|
|
31
88
|
function onBlur(event: Event) {
|
|
32
|
-
|
|
89
|
+
nextTick(() => {
|
|
33
90
|
isFocused.value = false;
|
|
34
91
|
emits('blur', event);
|
|
35
|
-
}
|
|
92
|
+
});
|
|
36
93
|
}
|
|
37
94
|
|
|
38
95
|
function onChange(event: Event) {
|
|
39
|
-
const value = (event
|
|
96
|
+
const value = getTargetValue(event);
|
|
40
97
|
validate(value);
|
|
41
98
|
emits('change', value);
|
|
42
99
|
}
|
|
43
100
|
|
|
44
|
-
function onInput(
|
|
45
|
-
const value = (
|
|
46
|
-
|
|
101
|
+
function onInput(event: Event) {
|
|
102
|
+
const value = getTargetValue(event);
|
|
103
|
+
internalValue.value = value;
|
|
47
104
|
isDirty.value = true;
|
|
48
105
|
validate(value);
|
|
49
106
|
emits('update:modelValue', value);
|
|
@@ -51,19 +108,15 @@
|
|
|
51
108
|
}
|
|
52
109
|
|
|
53
110
|
function onEnterKeydown(event: KeyboardEvent) {
|
|
54
|
-
const { altKey, ctrlKey, metaKey, shiftKey
|
|
55
|
-
const value = (target as HTMLInputElement).value;
|
|
111
|
+
const { altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
56
112
|
isDirty.value = true;
|
|
57
|
-
validate(value);
|
|
58
|
-
emits('
|
|
59
|
-
emits('enter', { value, altKey, ctrlKey, metaKey, shiftKey });
|
|
113
|
+
validate(internalValue.value);
|
|
114
|
+
emits('enter', { value: internalValue.value, altKey, ctrlKey, metaKey, shiftKey });
|
|
60
115
|
}
|
|
61
116
|
|
|
62
117
|
function onEscapeKeydown(event: KeyboardEvent) {
|
|
63
|
-
const value = (event.target as HTMLInputElement).value;
|
|
64
118
|
isDirty.value = true;
|
|
65
|
-
validate(value);
|
|
66
|
-
emits('update:modelValue', value);
|
|
119
|
+
validate(internalValue.value);
|
|
67
120
|
emits('escape', event);
|
|
68
121
|
}
|
|
69
122
|
|
|
@@ -72,31 +125,20 @@
|
|
|
72
125
|
}
|
|
73
126
|
|
|
74
127
|
function clearValue() {
|
|
75
|
-
|
|
128
|
+
internalValue.value = '';
|
|
76
129
|
isDirty.value = false;
|
|
77
|
-
|
|
130
|
+
errorMessage.value = '';
|
|
131
|
+
|
|
132
|
+
if (inputElement.value) {
|
|
133
|
+
inputElement.value.value = '';
|
|
134
|
+
inputElement.value.focus();
|
|
135
|
+
}
|
|
136
|
+
|
|
78
137
|
emits('update:modelValue', '');
|
|
79
138
|
emits('input', '');
|
|
80
139
|
emits('change', '');
|
|
81
140
|
emits('clear');
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
function validate(text: string) {
|
|
85
|
-
errorMessage.value = '';
|
|
86
|
-
if (props.rules && props.rules.length) {
|
|
87
|
-
for (const validateFunction of props.rules) {
|
|
88
|
-
if (typeof validateFunction === 'function') {
|
|
89
|
-
const res = validateFunction(text);
|
|
90
|
-
if (typeof res === 'string') {
|
|
91
|
-
errorMessage.value += `${res} `;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (isDirty.value) {
|
|
98
|
-
emits('update:valid', !errorMessage.value);
|
|
99
|
-
}
|
|
141
|
+
emits('update:valid', true);
|
|
100
142
|
}
|
|
101
143
|
|
|
102
144
|
defineExpose({
|
|
@@ -106,35 +148,34 @@
|
|
|
106
148
|
});
|
|
107
149
|
|
|
108
150
|
onMounted(() => {
|
|
109
|
-
|
|
110
|
-
|
|
151
|
+
internalValue.value = props.modelValue ?? '';
|
|
152
|
+
if (inputElement.value) {
|
|
153
|
+
inputElement.value.value = internalValue.value;
|
|
154
|
+
if (props.autofocus) {
|
|
155
|
+
inputElement.value.focus();
|
|
156
|
+
}
|
|
157
|
+
emits('init', inputElement.value);
|
|
111
158
|
}
|
|
112
159
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
validate(
|
|
116
|
-
}
|
|
117
|
-
if (!isInitialized.value) {
|
|
118
|
-
isInitialized.value = true;
|
|
160
|
+
if (props.validateAtStartup) {
|
|
161
|
+
isDirty.value = true;
|
|
162
|
+
validate(internalValue.value);
|
|
119
163
|
}
|
|
120
164
|
});
|
|
121
165
|
|
|
122
166
|
watch(
|
|
123
167
|
() => props.modelValue,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
168
|
+
val => {
|
|
169
|
+
const normalized = val ?? '';
|
|
170
|
+
if (normalized !== internalValue.value) {
|
|
171
|
+
internalValue.value = normalized;
|
|
127
172
|
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (!isInitialized.value) {
|
|
133
|
-
isInitialized.value = true;
|
|
173
|
+
if (inputElement.value) {
|
|
174
|
+
inputElement.value.value = normalized;
|
|
134
175
|
}
|
|
176
|
+
validate(normalized);
|
|
135
177
|
}
|
|
136
178
|
},
|
|
137
|
-
{ immediate: true },
|
|
138
179
|
);
|
|
139
180
|
</script>
|
|
140
181
|
|
|
@@ -142,10 +183,11 @@
|
|
|
142
183
|
<div
|
|
143
184
|
:class="[
|
|
144
185
|
$style.ui3nInput,
|
|
186
|
+
size === 'large' && $style.large,
|
|
145
187
|
label && $style.withLabel,
|
|
146
188
|
hideBottomSpace && $style.withoutBottomSpace,
|
|
147
189
|
icon && $style.withIcon,
|
|
148
|
-
clearable &&
|
|
190
|
+
clearable && internalValue && $style.clearable,
|
|
149
191
|
disabled && $style.disabled,
|
|
150
192
|
(!!errorMessage || displayStateMode === 'error') && $style.error,
|
|
151
193
|
displayStateMode === 'success' && $style.success,
|
|
@@ -161,8 +203,7 @@
|
|
|
161
203
|
<input
|
|
162
204
|
ref="inputElement"
|
|
163
205
|
autocomplete="off"
|
|
164
|
-
:type="type
|
|
165
|
-
:value="text"
|
|
206
|
+
:type="type"
|
|
166
207
|
:placeholder="placeholder"
|
|
167
208
|
:disabled="disabled"
|
|
168
209
|
:class="$style.ui3nInputField"
|
|
@@ -178,22 +219,20 @@
|
|
|
178
219
|
<ui3n-icon
|
|
179
220
|
v-if="icon"
|
|
180
221
|
:icon="icon"
|
|
181
|
-
:
|
|
182
|
-
:height="16"
|
|
222
|
+
:size="16"
|
|
183
223
|
:class="[$style.ui3nInputIcon, disabled && $style.ui3nInputIconDisabled]"
|
|
184
224
|
/>
|
|
185
225
|
|
|
186
226
|
<ui3n-icon
|
|
187
|
-
v-if="
|
|
227
|
+
v-if="showSuccessIcon"
|
|
188
228
|
icon="round-check-circle-outline"
|
|
189
|
-
:
|
|
190
|
-
:height="16"
|
|
229
|
+
:size="16"
|
|
191
230
|
color="var(--success-content-default)"
|
|
192
231
|
:class="$style.ui3nInputSuccessIcon"
|
|
193
232
|
/>
|
|
194
233
|
|
|
195
234
|
<ui3n-button
|
|
196
|
-
v-if="
|
|
235
|
+
v-if="showClearButton"
|
|
197
236
|
type="icon"
|
|
198
237
|
size="small"
|
|
199
238
|
color="transparent"
|
|
@@ -201,15 +240,17 @@
|
|
|
201
240
|
icon-size="16"
|
|
202
241
|
icon-color="var(--color-icon-control-accent-default)"
|
|
203
242
|
:class="$style.clearBtn"
|
|
243
|
+
@mousedown.prevent
|
|
244
|
+
@touchstart.prevent
|
|
204
245
|
@click="clearValue"
|
|
205
246
|
/>
|
|
206
247
|
|
|
207
248
|
<div
|
|
208
|
-
v-if="
|
|
249
|
+
v-if="showMessageBlock"
|
|
209
250
|
:class="[
|
|
210
251
|
$style.ui3nInputFieldMessage,
|
|
211
|
-
|
|
212
|
-
|
|
252
|
+
isErrorMessage && $style.ui3nInputErrorMessage,
|
|
253
|
+
isSuccessMessage && $style.ui3nInputSuccessMessage,
|
|
213
254
|
]"
|
|
214
255
|
>
|
|
215
256
|
{{ errorMessage || displayStateMessage }}
|
|
@@ -219,14 +260,41 @@
|
|
|
219
260
|
|
|
220
261
|
<style lang="scss" module>
|
|
221
262
|
.ui3nInput {
|
|
222
|
-
--ui3n-input-height:
|
|
263
|
+
--ui3n-input-height: 32px;
|
|
264
|
+
--ui3n-input-font-size: var(--font-13);
|
|
265
|
+
--ui3n-input-border-radius: var(--spacing-xs);
|
|
223
266
|
--ui3n-input-padding-left: var(--spacing-s);
|
|
224
267
|
--ui3n-input-padding-right: var(--spacing-s);
|
|
268
|
+
--ui3n-input-icon-size: 16px;
|
|
269
|
+
--ui3n-input-label-offset: calc(var(--font-16) + var(--spacing-xs));
|
|
270
|
+
--ui3n-input-message-top: calc(var(--ui3n-input-height) + var(--ui3n-input-label-offset) + 2px);
|
|
271
|
+
|
|
272
|
+
&:not(.withLabel) {
|
|
273
|
+
--ui3n-input-label-offset: 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
&.large {
|
|
277
|
+
--ui3n-input-height: 48px;
|
|
278
|
+
--ui3n-input-font-size: var(--font-16);
|
|
279
|
+
--ui3n-input-border-radius: 8px;
|
|
280
|
+
--ui3n-input-padding-left: 12px;
|
|
281
|
+
--ui3n-input-padding-right: 12px;
|
|
282
|
+
|
|
283
|
+
.clearBtn {
|
|
284
|
+
right: 2px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
&.withIcon {
|
|
288
|
+
.ui3nInputIcon {
|
|
289
|
+
left: 6px;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
225
293
|
|
|
226
294
|
position: relative;
|
|
227
295
|
width: 100%;
|
|
228
296
|
padding: 1px 1px 15px 1px;
|
|
229
|
-
border-radius: var(--
|
|
297
|
+
border-radius: var(--ui3n-input-border-radius);
|
|
230
298
|
|
|
231
299
|
&.withoutBottomSpace {
|
|
232
300
|
padding-bottom: 0;
|
|
@@ -249,7 +317,7 @@
|
|
|
249
317
|
}
|
|
250
318
|
|
|
251
319
|
.ui3nInputIcon {
|
|
252
|
-
color: v-bind(cssIconColor)
|
|
320
|
+
color: v-bind(cssIconColor);
|
|
253
321
|
}
|
|
254
322
|
}
|
|
255
323
|
}
|
|
@@ -273,22 +341,27 @@
|
|
|
273
341
|
outline: none;
|
|
274
342
|
height: var(--ui3n-input-height);
|
|
275
343
|
padding: 0 var(--ui3n-input-padding-right) 0 var(--ui3n-input-padding-left);
|
|
276
|
-
border-radius: var(--
|
|
344
|
+
border-radius: var(--ui3n-input-border-radius);
|
|
277
345
|
background-color: var(--color-bg-control-secondary-default);
|
|
278
|
-
font-size: var(--font-
|
|
279
|
-
line-height: var(--
|
|
346
|
+
font-size: var(--ui3n-input-font-size);
|
|
347
|
+
line-height: var(--spacing-m);
|
|
280
348
|
font-weight: 400;
|
|
281
349
|
color: var(--color-text-control-primary-default);
|
|
282
|
-
transition:
|
|
350
|
+
transition:
|
|
351
|
+
background-color 0.2s ease-in-out,
|
|
352
|
+
color 0.2s ease-in-out;
|
|
283
353
|
|
|
284
354
|
&::placeholder {
|
|
285
355
|
color: var(--color-text-control-secondary-default);
|
|
286
356
|
font-style: italic;
|
|
287
|
-
font-size: var(--font-
|
|
288
|
-
line-height: var(--font-16);
|
|
357
|
+
font-size: var(--ui3n-input-font-size);
|
|
289
358
|
font-weight: 400;
|
|
290
359
|
}
|
|
291
360
|
|
|
361
|
+
&:focus {
|
|
362
|
+
outline: none;
|
|
363
|
+
}
|
|
364
|
+
|
|
292
365
|
&[disabled] {
|
|
293
366
|
background-color: var(--color-bg-control-secondary-disabled);
|
|
294
367
|
color: var(--color-text-control-secondary-disabled);
|
|
@@ -297,13 +370,13 @@
|
|
|
297
370
|
|
|
298
371
|
.ui3nInputIcon {
|
|
299
372
|
position: absolute;
|
|
300
|
-
left: var(--
|
|
301
|
-
top: calc((var(--ui3n-input-height) -
|
|
302
|
-
color: var(--color-icon-control-secondary-default)
|
|
373
|
+
left: var(--spacing-xs);
|
|
374
|
+
top: calc((var(--ui3n-input-height) - var(--ui3n-input-icon-size)) / 2);
|
|
375
|
+
color: var(--color-icon-control-secondary-default);
|
|
303
376
|
}
|
|
304
377
|
|
|
305
378
|
.ui3nInputIconDisabled {
|
|
306
|
-
color: v-bind(cssIconColor)
|
|
379
|
+
color: v-bind(cssIconColor);
|
|
307
380
|
}
|
|
308
381
|
|
|
309
382
|
.clearBtn {
|
|
@@ -317,42 +390,50 @@
|
|
|
317
390
|
position: absolute;
|
|
318
391
|
left: 0;
|
|
319
392
|
width: 100%;
|
|
320
|
-
top:
|
|
393
|
+
top: calc(var(--ui3n-input-message-top) + 2px);
|
|
321
394
|
font-style: italic;
|
|
322
395
|
font-size: var(--font-10);
|
|
323
396
|
font-weight: 400;
|
|
324
397
|
line-height: 1.1;
|
|
398
|
+
}
|
|
325
399
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
400
|
+
.ui3nInputErrorMessage {
|
|
401
|
+
color: var(--error-content-default);
|
|
402
|
+
}
|
|
329
403
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
404
|
+
.ui3nInputSuccessMessage {
|
|
405
|
+
color: var(--success-content-default);
|
|
333
406
|
}
|
|
334
407
|
|
|
335
408
|
.clearable {
|
|
336
409
|
--ui3n-input-padding-right: var(--spacing-ml);
|
|
410
|
+
|
|
411
|
+
&.large {
|
|
412
|
+
--ui3n-input-padding-right: calc(var(--spacing-ml) + 4px);
|
|
413
|
+
}
|
|
337
414
|
}
|
|
338
415
|
|
|
339
416
|
.withIcon {
|
|
340
417
|
--ui3n-input-padding-left: var(--spacing-ml);
|
|
418
|
+
|
|
419
|
+
&.large {
|
|
420
|
+
--ui3n-input-padding-left: calc(var(--spacing-ml) + 4px);
|
|
421
|
+
}
|
|
341
422
|
}
|
|
342
423
|
|
|
343
424
|
.error {
|
|
344
425
|
.ui3nInputLabel {
|
|
345
|
-
color: var(--error-content-default)
|
|
426
|
+
color: var(--error-content-default);
|
|
346
427
|
}
|
|
347
428
|
|
|
348
429
|
.ui3nInputField {
|
|
349
|
-
outline: 1px solid var(--error-content-default)
|
|
430
|
+
outline: 1px solid var(--error-content-default);
|
|
350
431
|
}
|
|
351
432
|
}
|
|
352
433
|
|
|
353
434
|
.success {
|
|
354
435
|
.ui3nInputLabel {
|
|
355
|
-
color: var(--success-content-default)
|
|
436
|
+
color: var(--success-content-default);
|
|
356
437
|
}
|
|
357
438
|
}
|
|
358
439
|
|
|
@@ -369,16 +450,16 @@
|
|
|
369
450
|
|
|
370
451
|
.withLabel {
|
|
371
452
|
.ui3nInputIcon {
|
|
372
|
-
top: calc((var(--ui3n-input-height) -
|
|
453
|
+
top: calc((var(--ui3n-input-height) - var(--ui3n-input-icon-size)) / 2 + var(--ui3n-input-label-offset));
|
|
373
454
|
}
|
|
374
455
|
|
|
375
456
|
.ui3nInputSuccessIcon {
|
|
376
457
|
bottom: auto;
|
|
377
|
-
top: calc((var(--ui3n-input-height) -
|
|
458
|
+
top: calc((var(--ui3n-input-height) - var(--ui3n-input-icon-size)) / 2 + var(--ui3n-input-label-offset));
|
|
378
459
|
}
|
|
379
460
|
|
|
380
461
|
.clearBtn {
|
|
381
|
-
top: calc((var(--ui3n-input-height) - 24px) / 2 +
|
|
462
|
+
top: calc((var(--ui3n-input-height) - 24px) / 2 + var(--ui3n-input-label-offset));
|
|
382
463
|
z-index: 1;
|
|
383
464
|
}
|
|
384
465
|
}
|