bfg-common 1.5.232 → 1.5.234
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/assets/img/icons/icons-sprite-dark-3.svg +227 -227
- package/assets/img/icons/icons-sprite-dark-5.svg +488 -488
- package/assets/img/icons/icons-sprite-light-3.svg +227 -227
- package/assets/img/icons/icons-sprite-light-5.svg +488 -488
- package/assets/scss/common/icons/icons-1.scss +2 -2
- package/assets/scss/common/icons/icons-5.scss +5 -5
- package/assets/scss/common/icons/icons-6.scss +1 -1
- package/components/atoms/table/dataGrid/DataGrid.vue +2 -1
- package/components/atoms/table/info/lib/models/interfaces.ts +10 -10
- package/components/common/browse/blocks/lib/models/types.ts +1 -1
- package/components/common/browse/lib/models/interfaces.ts +5 -5
- package/components/common/context/recursion/RecursionNew.vue +18 -2
- package/components/common/diagramMain/adapter/AdapterItems.vue +61 -61
- package/components/common/diagramMain/lib/config/initial.ts +50 -50
- package/components/common/diagramMain/lib/models/types.ts +21 -21
- package/components/common/diagramMain/lib/utils/utils.ts +331 -331
- package/components/common/diagramMain/modals/editSettings/ConfirmTeamingSettingsModal.vue +40 -40
- package/components/common/diagramMain/modals/editSettings/tabs/NetworkProperties.vue +214 -214
- package/components/common/diagramMain/modals/editSettings/tabs/Security.vue +189 -189
- package/components/common/diagramMain/modals/editSettings/tabs/SwitchProperties.vue +163 -163
- package/components/common/diagramMain/modals/editSettings/tabs/TeamingFailover.vue +175 -175
- package/components/common/diagramMain/modals/editSettings/tabs/port/IpvFourSettings.vue +346 -346
- package/components/common/diagramMain/modals/lib/config/initial.ts +180 -180
- package/components/common/diagramMain/modals/lib/config/vmKernelAdapter.ts +90 -90
- package/components/common/diagramMain/modals/lib/mappers/mappers.ts +87 -87
- package/components/common/diagramMain/modals/lib/utils/index.ts +24 -24
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/lib/config/steps.ts +114 -114
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/steps/ConnectionSettings.vue +169 -169
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/steps/SelectVmkernelAdapter.vue +159 -159
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/validations/common.ts +14 -14
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/validations/connectionSettings.ts +137 -137
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/validations/selectVmkernelAdapter.ts +52 -52
- package/components/common/diagramMain/modals/migrateVmkernelAdapter/validations/validations.ts +19 -19
- package/components/common/diagramMain/port/Ports.vue +47 -47
- package/package.json +2 -2
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
background-position: 0 98.7%;
|
|
94
94
|
}
|
|
95
95
|
.storage-ui-icon-increase_datastore {
|
|
96
|
-
background-position: 0 94.
|
|
96
|
+
background-position: 0 94.9%;
|
|
97
97
|
}
|
|
98
98
|
.storage-ui-icon-datastore-unmount {
|
|
99
99
|
background-position: 0 100%;
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
background-position: 0 43.0379746835%;
|
|
115
115
|
}
|
|
116
116
|
.storage-ui-icon-browse-file {
|
|
117
|
-
background-position: 0 30.
|
|
117
|
+
background-position: 0 30.3797468354%;
|
|
118
118
|
}
|
|
119
119
|
.clone-to-template {
|
|
120
120
|
background-position: 0 46.8%;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
background-position: 0 7.59%;
|
|
14
14
|
}
|
|
15
15
|
.vx-icon-vmMigrate {
|
|
16
|
-
background-position: 0 1.
|
|
16
|
+
background-position: 0 1.3%;
|
|
17
17
|
}
|
|
18
18
|
.network-lib-ui-icon-vswitch {
|
|
19
19
|
background-position: 0 24.05%;
|
|
@@ -59,16 +59,16 @@
|
|
|
59
59
|
background-position: 0 40.5%;
|
|
60
60
|
}
|
|
61
61
|
.icon-web-terminal {
|
|
62
|
-
background-position: 0 41.
|
|
62
|
+
background-position: 0 41.8%;
|
|
63
63
|
}
|
|
64
64
|
.icon-move {
|
|
65
|
-
background-position: 0 43
|
|
65
|
+
background-position: 0 43%;
|
|
66
66
|
}
|
|
67
67
|
.icon-settings {
|
|
68
68
|
background-position: 0 44.3%;
|
|
69
69
|
}
|
|
70
70
|
.icon-remove {
|
|
71
|
-
background-position: 0 45.
|
|
71
|
+
background-position: 0 45.6%;
|
|
72
72
|
}
|
|
73
73
|
.icon-backup-storage {
|
|
74
74
|
background-position: 0 46.8%;
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
background-position: 0 68.3%;
|
|
114
114
|
}
|
|
115
115
|
.icon-edit {
|
|
116
|
-
background-position: 0 69.
|
|
116
|
+
background-position: 0 69.6%;
|
|
117
117
|
}
|
|
118
118
|
.icon-backup {
|
|
119
119
|
background-position: 0 62%;
|
|
@@ -819,10 +819,11 @@ const headItemsPresent = computed<UI_I_HeadItem[]>(() => {
|
|
|
819
819
|
const bodyItemsPresent = computed<UI_I_BodyItem[][]>(() => {
|
|
820
820
|
let items: UI_I_BodyItem[][] = props.bodyItems.map((row) => {
|
|
821
821
|
return row.map((item) => {
|
|
822
|
+
const text = item.text.toString()
|
|
822
823
|
return {
|
|
823
824
|
...item,
|
|
824
825
|
// Если текст пустой нужно поставить '--' для экспорта
|
|
825
|
-
text:
|
|
826
|
+
text: text.trim() !== '' ? text : '--',
|
|
826
827
|
}
|
|
827
828
|
})
|
|
828
829
|
})
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export interface UI_I_TableInfoItem {
|
|
2
|
-
label: string
|
|
3
|
-
value: any
|
|
4
|
-
isProperty?: boolean
|
|
5
|
-
key?: string
|
|
6
|
-
localization?: string
|
|
7
|
-
localizationTemplate?: string
|
|
8
|
-
isCapital?: boolean
|
|
9
|
-
iconName?: string
|
|
10
|
-
}
|
|
1
|
+
export interface UI_I_TableInfoItem {
|
|
2
|
+
label: string
|
|
3
|
+
value: any
|
|
4
|
+
isProperty?: boolean
|
|
5
|
+
key?: string
|
|
6
|
+
localization?: string
|
|
7
|
+
localizationTemplate?: string
|
|
8
|
+
isCapital?: boolean
|
|
9
|
+
iconName?: string
|
|
10
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type UI_T_BlocksWidth = [number, number, number]
|
|
1
|
+
export type UI_T_BlocksWidth = [number, number, number]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export interface UI_I_FileInfo {
|
|
2
|
-
type: string
|
|
3
|
-
title: string
|
|
4
|
-
value: string | number
|
|
5
|
-
}
|
|
1
|
+
export interface UI_I_FileInfo {
|
|
2
|
+
type: string
|
|
3
|
+
title: string
|
|
4
|
+
value: string | number
|
|
5
|
+
}
|
|
@@ -18,7 +18,12 @@
|
|
|
18
18
|
@mouseleave="emits('toggle-items', [item, false, $event])"
|
|
19
19
|
>
|
|
20
20
|
<span
|
|
21
|
-
class="
|
|
21
|
+
:class="[
|
|
22
|
+
'context-link',
|
|
23
|
+
{
|
|
24
|
+
'without-children': allInBlockWithoutChildren,
|
|
25
|
+
},
|
|
26
|
+
]"
|
|
22
27
|
:style="item.style"
|
|
23
28
|
:data-id="`${item.testId}-context-link`"
|
|
24
29
|
@mousedown="emits('select-item', item)"
|
|
@@ -68,6 +73,13 @@ const emits = defineEmits<{
|
|
|
68
73
|
value: [UI_I_ContextMenuItem, boolean, I_HTMLLiElement]
|
|
69
74
|
): void
|
|
70
75
|
}>()
|
|
76
|
+
|
|
77
|
+
const allInBlockWithoutChildren = computed<boolean>(
|
|
78
|
+
() =>
|
|
79
|
+
!props.items.filter(
|
|
80
|
+
(item: UI_I_ContextMenuItem) => item.items && item.items.length > 0
|
|
81
|
+
).length
|
|
82
|
+
)
|
|
71
83
|
</script>
|
|
72
84
|
|
|
73
85
|
<style>
|
|
@@ -203,6 +215,10 @@ const emits = defineEmits<{
|
|
|
203
215
|
border-radius: 4px;
|
|
204
216
|
padding: 6px 24px 6px 8px;
|
|
205
217
|
|
|
218
|
+
&.without-children {
|
|
219
|
+
padding: 6px 10px 6px 8px;
|
|
220
|
+
}
|
|
221
|
+
|
|
206
222
|
.menu-item-text {
|
|
207
223
|
flex: 1 1 0;
|
|
208
224
|
font-size: 13px;
|
|
@@ -230,7 +246,7 @@ const emits = defineEmits<{
|
|
|
230
246
|
|
|
231
247
|
.shortcut {
|
|
232
248
|
color: #9da6ad;
|
|
233
|
-
padding-left:
|
|
249
|
+
padding-left: 16px;
|
|
234
250
|
}
|
|
235
251
|
}
|
|
236
252
|
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<g data-title="adapter-items-group">
|
|
3
|
-
<template v-if="props.adaptersWithPositions.toggle">
|
|
4
|
-
<template
|
|
5
|
-
v-for="(adapter, key) in props.adaptersWithPositions.adapters"
|
|
6
|
-
:key="adapter.id"
|
|
7
|
-
>
|
|
8
|
-
<common-diagram-main-adapter-item
|
|
9
|
-
:adapter="adapter"
|
|
10
|
-
:selected-port="props.selectedPort"
|
|
11
|
-
:selected-adapter="props.selectedAdapter"
|
|
12
|
-
:networks-count="props.networksCount"
|
|
13
|
-
:is-dark-mode="props.isDarkMode"
|
|
14
|
-
:networks-with-positions="props.networksWithPositions"
|
|
15
|
-
@select-adapter="onSelectAdapter"
|
|
16
|
-
@show-modal="onShowModal"
|
|
17
|
-
/>
|
|
18
|
-
</template>
|
|
19
|
-
</template>
|
|
20
|
-
</g>
|
|
21
|
-
</template>
|
|
22
|
-
|
|
23
|
-
<script setup lang="ts">
|
|
24
|
-
import {
|
|
25
|
-
UI_I_AdaptersWithPositions,
|
|
26
|
-
UI_I_ModalsInitialData,
|
|
27
|
-
UI_I_SelectedAdapter,
|
|
28
|
-
UI_I_SelectedPort,
|
|
29
|
-
UI_I_NetworksWithPositions,
|
|
30
|
-
} from '~/components/common/diagramMain/lib/models/interfaces'
|
|
31
|
-
|
|
32
|
-
const props = defineProps<{
|
|
33
|
-
adaptersWithPositions: UI_I_AdaptersWithPositions
|
|
34
|
-
networksWithPositions: UI_I_NetworksWithPositions[]
|
|
35
|
-
selectedPort: UI_I_SelectedPort
|
|
36
|
-
selectedAdapter: UI_I_SelectedAdapter
|
|
37
|
-
networksCount: number
|
|
38
|
-
isDarkMode: boolean
|
|
39
|
-
}>()
|
|
40
|
-
|
|
41
|
-
const emits = defineEmits<{
|
|
42
|
-
(event: 'select-adapter', adapterId: string): void
|
|
43
|
-
(
|
|
44
|
-
event: 'show-modal',
|
|
45
|
-
value: string,
|
|
46
|
-
properties?: UI_I_ModalsInitialData
|
|
47
|
-
): void
|
|
48
|
-
}>()
|
|
49
|
-
|
|
50
|
-
const onSelectAdapter = (adapterId: string): void => {
|
|
51
|
-
emits('select-adapter', adapterId)
|
|
52
|
-
}
|
|
53
|
-
const onShowModal = (
|
|
54
|
-
value: string,
|
|
55
|
-
properties?: UI_I_ModalsInitialData
|
|
56
|
-
): void => {
|
|
57
|
-
emits('show-modal', value, properties)
|
|
58
|
-
}
|
|
59
|
-
</script>
|
|
60
|
-
|
|
61
|
-
<style scoped lang="scss"></style>
|
|
1
|
+
<template>
|
|
2
|
+
<g data-title="adapter-items-group">
|
|
3
|
+
<template v-if="props.adaptersWithPositions.toggle">
|
|
4
|
+
<template
|
|
5
|
+
v-for="(adapter, key) in props.adaptersWithPositions.adapters"
|
|
6
|
+
:key="adapter.id"
|
|
7
|
+
>
|
|
8
|
+
<common-diagram-main-adapter-item
|
|
9
|
+
:adapter="adapter"
|
|
10
|
+
:selected-port="props.selectedPort"
|
|
11
|
+
:selected-adapter="props.selectedAdapter"
|
|
12
|
+
:networks-count="props.networksCount"
|
|
13
|
+
:is-dark-mode="props.isDarkMode"
|
|
14
|
+
:networks-with-positions="props.networksWithPositions"
|
|
15
|
+
@select-adapter="onSelectAdapter"
|
|
16
|
+
@show-modal="onShowModal"
|
|
17
|
+
/>
|
|
18
|
+
</template>
|
|
19
|
+
</template>
|
|
20
|
+
</g>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup lang="ts">
|
|
24
|
+
import {
|
|
25
|
+
UI_I_AdaptersWithPositions,
|
|
26
|
+
UI_I_ModalsInitialData,
|
|
27
|
+
UI_I_SelectedAdapter,
|
|
28
|
+
UI_I_SelectedPort,
|
|
29
|
+
UI_I_NetworksWithPositions,
|
|
30
|
+
} from '~/components/common/diagramMain/lib/models/interfaces'
|
|
31
|
+
|
|
32
|
+
const props = defineProps<{
|
|
33
|
+
adaptersWithPositions: UI_I_AdaptersWithPositions
|
|
34
|
+
networksWithPositions: UI_I_NetworksWithPositions[]
|
|
35
|
+
selectedPort: UI_I_SelectedPort
|
|
36
|
+
selectedAdapter: UI_I_SelectedAdapter
|
|
37
|
+
networksCount: number
|
|
38
|
+
isDarkMode: boolean
|
|
39
|
+
}>()
|
|
40
|
+
|
|
41
|
+
const emits = defineEmits<{
|
|
42
|
+
(event: 'select-adapter', adapterId: string): void
|
|
43
|
+
(
|
|
44
|
+
event: 'show-modal',
|
|
45
|
+
value: string,
|
|
46
|
+
properties?: UI_I_ModalsInitialData
|
|
47
|
+
): void
|
|
48
|
+
}>()
|
|
49
|
+
|
|
50
|
+
const onSelectAdapter = (adapterId: string): void => {
|
|
51
|
+
emits('select-adapter', adapterId)
|
|
52
|
+
}
|
|
53
|
+
const onShowModal = (
|
|
54
|
+
value: string,
|
|
55
|
+
properties?: UI_I_ModalsInitialData
|
|
56
|
+
): void => {
|
|
57
|
+
emits('show-modal', value, properties)
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<style scoped lang="scss"></style>
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
UI_I_AdapterStatus,
|
|
3
|
-
UI_I_MainRectHeights,
|
|
4
|
-
UI_I_SelectedAdapter,
|
|
5
|
-
UI_I_SelectedPort,
|
|
6
|
-
UI_I_SwitchLine,
|
|
7
|
-
UI_I_NetworkPositionsConst,
|
|
8
|
-
} from '~/components/common/diagramMain/lib/models/interfaces'
|
|
9
|
-
|
|
10
|
-
export const managePhysicalAdapterStatusInitial: UI_I_AdapterStatus = {
|
|
11
|
-
active: [],
|
|
12
|
-
standby: [],
|
|
13
|
-
unused: [],
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const mainRectHeightsInitial: UI_I_MainRectHeights = {
|
|
17
|
-
networksHeight: 0,
|
|
18
|
-
adaptersHeight: 0,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const switchLineInitial: UI_I_SwitchLine = {
|
|
22
|
-
y1: 0,
|
|
23
|
-
y2: 0,
|
|
24
|
-
ay: 0,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const selectedPortInitial: UI_I_SelectedPort = {
|
|
28
|
-
networkId: '-1',
|
|
29
|
-
portId: '-1',
|
|
30
|
-
activeAdapters: [],
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const selectedAdapterInitial: UI_I_SelectedAdapter = {
|
|
34
|
-
adapterId: '-1',
|
|
35
|
-
connectedPorts: [],
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const selectedSwitchLineYInitial: UI_I_SwitchLine = {
|
|
39
|
-
y1: 0,
|
|
40
|
-
y2: 0,
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const NETWORK_POSITIONS: UI_I_NetworkPositionsConst = {
|
|
44
|
-
EMPTY_PORTS_PADDING_BOTTOM: 7.5,
|
|
45
|
-
FROM_VLAN_ID_TO_GROUP_NAME: 22,
|
|
46
|
-
VMS_AND_PORTS_HEIGHT: 22,
|
|
47
|
-
V_CENTER_HEIGHT: 32,
|
|
48
|
-
BETWEEN_VMS_AND_PORTS: 7.5,
|
|
49
|
-
BETWEEN_V_CENTERS: 12.5,
|
|
50
|
-
} as const
|
|
1
|
+
import type {
|
|
2
|
+
UI_I_AdapterStatus,
|
|
3
|
+
UI_I_MainRectHeights,
|
|
4
|
+
UI_I_SelectedAdapter,
|
|
5
|
+
UI_I_SelectedPort,
|
|
6
|
+
UI_I_SwitchLine,
|
|
7
|
+
UI_I_NetworkPositionsConst,
|
|
8
|
+
} from '~/components/common/diagramMain/lib/models/interfaces'
|
|
9
|
+
|
|
10
|
+
export const managePhysicalAdapterStatusInitial: UI_I_AdapterStatus = {
|
|
11
|
+
active: [],
|
|
12
|
+
standby: [],
|
|
13
|
+
unused: [],
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const mainRectHeightsInitial: UI_I_MainRectHeights = {
|
|
17
|
+
networksHeight: 0,
|
|
18
|
+
adaptersHeight: 0,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const switchLineInitial: UI_I_SwitchLine = {
|
|
22
|
+
y1: 0,
|
|
23
|
+
y2: 0,
|
|
24
|
+
ay: 0,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const selectedPortInitial: UI_I_SelectedPort = {
|
|
28
|
+
networkId: '-1',
|
|
29
|
+
portId: '-1',
|
|
30
|
+
activeAdapters: [],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const selectedAdapterInitial: UI_I_SelectedAdapter = {
|
|
34
|
+
adapterId: '-1',
|
|
35
|
+
connectedPorts: [],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const selectedSwitchLineYInitial: UI_I_SwitchLine = {
|
|
39
|
+
y1: 0,
|
|
40
|
+
y2: 0,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const NETWORK_POSITIONS: UI_I_NetworkPositionsConst = {
|
|
44
|
+
EMPTY_PORTS_PADDING_BOTTOM: 7.5,
|
|
45
|
+
FROM_VLAN_ID_TO_GROUP_NAME: 22,
|
|
46
|
+
VMS_AND_PORTS_HEIGHT: 22,
|
|
47
|
+
V_CENTER_HEIGHT: 32,
|
|
48
|
+
BETWEEN_VMS_AND_PORTS: 7.5,
|
|
49
|
+
BETWEEN_V_CENTERS: 12.5,
|
|
50
|
+
} as const
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
UI_I_Adapter,
|
|
3
|
-
UI_I_AdapterWithError,
|
|
4
|
-
} from '~/components/common/diagramMain/lib/models/interfaces'
|
|
5
|
-
|
|
6
|
-
export type UI_T_AdapterStatusNames = 'active' | 'standby' | 'unused'
|
|
7
|
-
export type UI_T_PropertiesFieldName = 'vlanId' | 'networkLabel'
|
|
8
|
-
export type UI_T_TrafficShapingFieldName = 'average' | 'peak' | 'burstSize'
|
|
9
|
-
export type UI_T_PortPropertiesFieldName = 'mtu'
|
|
10
|
-
|
|
11
|
-
export type UI_T_LoadBalancingMode =
|
|
12
|
-
| 'inherit'
|
|
13
|
-
| 'active-backup'
|
|
14
|
-
| 'balance-slb'
|
|
15
|
-
| 'balance-tcp'
|
|
16
|
-
export type UI_T_IYN = 'inherit' | 'yes' | 'no'
|
|
17
|
-
export type UI_T_Carier = 'inherit' | 'carier' | 'beakon'
|
|
18
|
-
|
|
19
|
-
export type UI_T_Adapters = (UI_I_Adapter | UI_I_AdapterWithError) & {
|
|
20
|
-
adapterPosition: number
|
|
21
|
-
}
|
|
1
|
+
import type {
|
|
2
|
+
UI_I_Adapter,
|
|
3
|
+
UI_I_AdapterWithError,
|
|
4
|
+
} from '~/components/common/diagramMain/lib/models/interfaces'
|
|
5
|
+
|
|
6
|
+
export type UI_T_AdapterStatusNames = 'active' | 'standby' | 'unused'
|
|
7
|
+
export type UI_T_PropertiesFieldName = 'vlanId' | 'networkLabel'
|
|
8
|
+
export type UI_T_TrafficShapingFieldName = 'average' | 'peak' | 'burstSize'
|
|
9
|
+
export type UI_T_PortPropertiesFieldName = 'mtu'
|
|
10
|
+
|
|
11
|
+
export type UI_T_LoadBalancingMode =
|
|
12
|
+
| 'inherit'
|
|
13
|
+
| 'active-backup'
|
|
14
|
+
| 'balance-slb'
|
|
15
|
+
| 'balance-tcp'
|
|
16
|
+
export type UI_T_IYN = 'inherit' | 'yes' | 'no'
|
|
17
|
+
export type UI_T_Carier = 'inherit' | 'carier' | 'beakon'
|
|
18
|
+
|
|
19
|
+
export type UI_T_Adapters = (UI_I_Adapter | UI_I_AdapterWithError) & {
|
|
20
|
+
adapterPosition: number
|
|
21
|
+
}
|