vanilla-framework 4.9.1 → 4.11.0
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/package.json +9 -10
- package/scss/_base_blockquotes.scss +1 -1
- package/scss/_base_button.scss +2 -0
- package/scss/_base_code.scss +0 -8
- package/scss/_base_forms-range.scss +6 -5
- package/scss/_base_forms.scss +3 -8
- package/scss/_base_icon-definitions.scss +1 -1
- package/scss/_base_placeholders.scss +2 -0
- package/scss/_patterns_buttons.scss +3 -11
- package/scss/_patterns_card.scss +2 -1
- package/scss/_patterns_chip.scss +10 -15
- package/scss/_patterns_equal-height-row.scss +107 -0
- package/scss/_patterns_icons.scss +3 -95
- package/scss/_patterns_lists.scss +3 -3
- package/scss/_patterns_media-container.scss +5 -0
- package/scss/_patterns_navigation.scss +113 -245
- package/scss/_patterns_notifications.scss +0 -1
- package/scss/_patterns_pagination.scss +2 -2
- package/scss/_patterns_rule.scss +2 -10
- package/scss/_patterns_suru.scss +35 -4
- package/scss/_settings_colors.scss +2 -2
- package/scss/_settings_spacing.scss +4 -4
- package/scss/_settings_themes.scss +9 -6
- package/scss/_utilities_layout.scss +10 -4
- package/scss/_vanilla.scss +13 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-framework",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"author": {
|
|
5
5
|
"email": "webteam@canonical.com",
|
|
6
6
|
"name": "Canonical Webteam"
|
|
@@ -55,25 +55,24 @@
|
|
|
55
55
|
"!/scss/standalone"
|
|
56
56
|
],
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@canonical/cookie-policy": "3.
|
|
58
|
+
"@canonical/cookie-policy": "3.6.3",
|
|
59
59
|
"@canonical/latest-news": "1.5.0",
|
|
60
|
-
"@percy/cli": "1.28.
|
|
60
|
+
"@percy/cli": "1.28.5",
|
|
61
61
|
"@testing-library/cypress": "10.0.1",
|
|
62
|
-
"autoprefixer": "10.4.
|
|
63
|
-
"cypress": "13.
|
|
64
|
-
"get-site-urls": "3.0.0",
|
|
62
|
+
"autoprefixer": "10.4.19",
|
|
63
|
+
"cypress": "13.8.1",
|
|
65
64
|
"markdown-spellcheck": "1.3.1",
|
|
66
65
|
"parker": "0.0.10",
|
|
67
|
-
"postcss": "8.4.
|
|
66
|
+
"postcss": "8.4.38",
|
|
68
67
|
"postcss-cli": "11.0.0",
|
|
69
68
|
"postcss-scss": "4.0.9",
|
|
70
69
|
"prettier": "3.2.5",
|
|
71
|
-
"sass": "1.
|
|
72
|
-
"stylelint": "16.
|
|
70
|
+
"sass": "1.77.0",
|
|
71
|
+
"stylelint": "16.5.0",
|
|
73
72
|
"stylelint-config-recommended-scss": "14.0.0",
|
|
74
73
|
"stylelint-order": "6.0.4",
|
|
75
74
|
"stylelint-prettier": "5.0.0",
|
|
76
75
|
"svgo": "3.2.0",
|
|
77
|
-
"yaml": "2.4.
|
|
76
|
+
"yaml": "2.4.2"
|
|
78
77
|
}
|
|
79
78
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
@mixin vf-b-blockquotes {
|
|
5
5
|
// stylelint-disable selector-max-type -- base styles can use type selectors
|
|
6
6
|
blockquote {
|
|
7
|
-
border-left: 2px solid $
|
|
7
|
+
border-left: 2px solid $colors--theme--border-high-contrast;
|
|
8
8
|
margin-bottom: $spv--x-large;
|
|
9
9
|
margin-left: 0;
|
|
10
10
|
margin-top: 0;
|
package/scss/_base_button.scss
CHANGED
|
@@ -77,6 +77,8 @@
|
|
|
77
77
|
// stylelint-enable selector-max-type
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
// FIXME: buttons are using a custom version of success icon that is not themed
|
|
81
|
+
// this should ideally be replaced with a themed icon that uses text colour
|
|
80
82
|
%vf-button-white-success-icon {
|
|
81
83
|
& .p-icon--success {
|
|
82
84
|
@include vf-icon-success($color-x-light, $color-transparent);
|
package/scss/_base_code.scss
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
@import 'settings';
|
|
2
2
|
|
|
3
|
-
$color-pre-bg: rgba($color-x-dark, 0.03);
|
|
4
3
|
$digit-width: 1ch; // measured width of one character in the monospaced font
|
|
5
4
|
$code-sidebar-width: calc($sph--large + (4 * $digit-width)) !default;
|
|
6
5
|
$code-inline-padding: 0.25rem;
|
|
@@ -71,13 +70,6 @@ $code-inline-padding: 0.25rem;
|
|
|
71
70
|
white-space: pre;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
// dark theme
|
|
75
|
-
[class*='--dark'] code,
|
|
76
|
-
code.is-dark {
|
|
77
|
-
background-color: $color-code-background-dark;
|
|
78
|
-
color: $colors--dark-theme--text-default;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
73
|
%leading-linux-prompt-icon {
|
|
82
74
|
&::before {
|
|
83
75
|
@extend %icon;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
$thumb-shadow: 0 0 $bar-thickness 1px rgba(0, 0, 0, 0.2);
|
|
3
3
|
$thumb-size: 1rem;
|
|
4
4
|
$thumb-radius: 50%;
|
|
5
|
-
$thumb-border: $input-border-thickness solid $
|
|
5
|
+
$thumb-border: $input-border-thickness solid $colors--theme--border-high-contrast;
|
|
6
6
|
$track-height: $bar-thickness;
|
|
7
7
|
$track-radius: $bar-thickness;
|
|
8
8
|
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
-moz-appearance: none;
|
|
14
14
|
appearance: none;
|
|
15
15
|
// stylelint-enable property-no-vendor-prefix
|
|
16
|
+
background-color: $color-transparent;
|
|
16
17
|
border-radius: $track-radius;
|
|
17
18
|
margin: $sp-small 0;
|
|
18
19
|
padding: 0;
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
-moz-appearance: none;
|
|
31
32
|
appearance: none;
|
|
32
33
|
// stylelint-enable property-no-vendor-prefix
|
|
33
|
-
background: $
|
|
34
|
+
background: $colors--theme--background-default;
|
|
34
35
|
border: $thumb-border;
|
|
35
36
|
border-radius: $thumb-radius;
|
|
36
37
|
box-shadow: $thumb-shadow;
|
|
@@ -45,19 +46,19 @@
|
|
|
45
46
|
|
|
46
47
|
// Firefox
|
|
47
48
|
&::-moz-range-track {
|
|
48
|
-
background: $
|
|
49
|
+
background: $colors--theme--border-default; // default; //mid-light;
|
|
49
50
|
border-radius: $track-radius;
|
|
50
51
|
height: $track-height;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
&::-moz-range-progress {
|
|
54
|
-
background-color: $
|
|
55
|
+
background-color: $colors--theme--link-default; //-link;
|
|
55
56
|
border-radius: $track-radius;
|
|
56
57
|
height: $track-height;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
&::-moz-range-thumb {
|
|
60
|
-
background: $
|
|
61
|
+
background: $colors--theme--background-default; // x-light;
|
|
61
62
|
border: $thumb-border;
|
|
62
63
|
border-radius: $thumb-radius;
|
|
63
64
|
box-shadow: $thumb-shadow;
|
package/scss/_base_forms.scss
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// Default form input element styles
|
|
14
14
|
%vf-input-elements {
|
|
15
15
|
@extend %bordered-text-vertical-padding;
|
|
16
|
-
@include vf-focus($
|
|
16
|
+
@include vf-focus($has-validation: true);
|
|
17
17
|
@include vf-animation(#{background-color}, fast);
|
|
18
18
|
|
|
19
19
|
// stylelint-disable property-no-vendor-prefix
|
|
@@ -93,20 +93,15 @@
|
|
|
93
93
|
|
|
94
94
|
// Readonly form elements
|
|
95
95
|
%vf-readonly-element {
|
|
96
|
-
color: $
|
|
96
|
+
color: $colors--theme--text-muted;
|
|
97
97
|
cursor: default;
|
|
98
|
-
|
|
99
|
-
&:hover,
|
|
100
|
-
&:active {
|
|
101
|
-
border-color: $color-mid-dark;
|
|
102
|
-
outline: none;
|
|
103
|
-
}
|
|
104
98
|
}
|
|
105
99
|
|
|
106
100
|
// stylelint-disable selector-max-type -- base styles can use type selectors
|
|
107
101
|
label {
|
|
108
102
|
cursor: pointer;
|
|
109
103
|
display: inline-block;
|
|
104
|
+
line-height: map-get($line-heights, default-text);
|
|
110
105
|
margin-bottom: $spv--large - $spv-nudge;
|
|
111
106
|
margin-top: 0;
|
|
112
107
|
max-width: $text-max-width;
|
|
@@ -25,11 +25,13 @@
|
|
|
25
25
|
border: $border;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// deprecated -- use the theme colour variables
|
|
28
29
|
%vf-bg--light {
|
|
29
30
|
background-color: $color-light;
|
|
30
31
|
color: $colors--light-theme--text-default;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
// deprecated -- use the theme colour variables
|
|
33
35
|
%vf-bg--x-light {
|
|
34
36
|
background-color: $color-x-light;
|
|
35
37
|
color: $colors--light-theme--text-default;
|
|
@@ -54,18 +54,10 @@
|
|
|
54
54
|
@extend %vf-button-base;
|
|
55
55
|
|
|
56
56
|
// Theming
|
|
57
|
-
@
|
|
58
|
-
@extend %p-button--brand-dark;
|
|
59
|
-
|
|
60
|
-
&.is-light {
|
|
61
|
-
@extend %p-button--brand-light;
|
|
62
|
-
}
|
|
63
|
-
} @else {
|
|
64
|
-
@extend %p-button--brand-light;
|
|
57
|
+
@extend %p-button--brand-light;
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
59
|
+
&.is-dark {
|
|
60
|
+
@extend %p-button--brand-dark;
|
|
69
61
|
}
|
|
70
62
|
|
|
71
63
|
@extend %vf-button-white-success-icon;
|
package/scss/_patterns_card.scss
CHANGED
|
@@ -40,9 +40,10 @@
|
|
|
40
40
|
|
|
41
41
|
@mixin vf-p-card-muted {
|
|
42
42
|
.p-card--muted {
|
|
43
|
-
@extend %vf-bg--light;
|
|
44
43
|
@extend %vf-has-box-shadow;
|
|
45
44
|
|
|
45
|
+
background-color: $color-light;
|
|
46
|
+
color: $colors--light-theme--text-default;
|
|
46
47
|
margin-bottom: $spv--x-large;
|
|
47
48
|
overflow: auto;
|
|
48
49
|
padding: $spv--large;
|
package/scss/_patterns_chip.scss
CHANGED
|
@@ -82,15 +82,13 @@ $chip-border-thickness: 1px;
|
|
|
82
82
|
border-color: $colors--theme--border-neutral;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// stylelint-disable
|
|
85
|
+
// stylelint-disable selector-max-type -- allow button selector for interactive chips
|
|
86
86
|
button.p-chip {
|
|
87
|
-
// stylelint-disable-next-line selector-max-type
|
|
88
87
|
&:hover {
|
|
89
88
|
background-color: $colors--theme--background-neutral-hover;
|
|
90
89
|
border-color: $colors--theme--border-neutral;
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
// stylelint-disable-next-line selector-max-type
|
|
94
92
|
&[aria-pressed='true'],
|
|
95
93
|
&.is-selected,
|
|
96
94
|
&:active {
|
|
@@ -98,6 +96,7 @@ $chip-border-thickness: 1px;
|
|
|
98
96
|
border-color: $colors--theme--border-neutral;
|
|
99
97
|
}
|
|
100
98
|
}
|
|
99
|
+
// stylelint-enable selector-max-type
|
|
101
100
|
|
|
102
101
|
.p-chip .p-chip__dismiss {
|
|
103
102
|
@include vf-button-pattern(
|
|
@@ -120,15 +119,13 @@ $chip-border-thickness: 1px;
|
|
|
120
119
|
border-color: $colors--theme--border-positive;
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
// stylelint-disable
|
|
122
|
+
// stylelint-disable selector-max-type -- allow button selector for interactive chips
|
|
124
123
|
button.p-chip--positive {
|
|
125
|
-
// stylelint-disable-next-line selector-max-type
|
|
126
124
|
&:hover {
|
|
127
125
|
background-color: $colors--theme--background-positive-hover;
|
|
128
126
|
border-color: $colors--theme--border-positive;
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
// stylelint-disable-next-line selector-max-type
|
|
132
129
|
&[aria-pressed='true'],
|
|
133
130
|
&.is-selected,
|
|
134
131
|
&:active {
|
|
@@ -136,6 +133,7 @@ $chip-border-thickness: 1px;
|
|
|
136
133
|
border-color: $colors--theme--border-positive;
|
|
137
134
|
}
|
|
138
135
|
}
|
|
136
|
+
// stylelint-enable selector-max-type
|
|
139
137
|
|
|
140
138
|
.p-chip--positive .p-chip__dismiss {
|
|
141
139
|
@include vf-button-pattern(
|
|
@@ -158,15 +156,13 @@ $chip-border-thickness: 1px;
|
|
|
158
156
|
border-color: $colors--theme--border-caution;
|
|
159
157
|
}
|
|
160
158
|
|
|
161
|
-
// stylelint-disable
|
|
159
|
+
// stylelint-disable selector-max-type -- allow button selector for interactive chips
|
|
162
160
|
button.p-chip--caution {
|
|
163
|
-
// stylelint-disable-next-line selector-max-type
|
|
164
161
|
&:hover {
|
|
165
162
|
background-color: $colors--theme--background-caution-hover;
|
|
166
163
|
border-color: $colors--theme--border-caution;
|
|
167
164
|
}
|
|
168
165
|
|
|
169
|
-
// stylelint-disable-next-line selector-max-type
|
|
170
166
|
&[aria-pressed='true'],
|
|
171
167
|
&.is-selected,
|
|
172
168
|
&:active {
|
|
@@ -174,6 +170,7 @@ $chip-border-thickness: 1px;
|
|
|
174
170
|
border-color: $colors--theme--border-caution;
|
|
175
171
|
}
|
|
176
172
|
}
|
|
173
|
+
// stylelint-enable selector-max-type
|
|
177
174
|
|
|
178
175
|
.p-chip--caution .p-chip__dismiss {
|
|
179
176
|
@include vf-button-pattern(
|
|
@@ -196,15 +193,13 @@ $chip-border-thickness: 1px;
|
|
|
196
193
|
border-color: $colors--theme--border-negative;
|
|
197
194
|
}
|
|
198
195
|
|
|
199
|
-
// stylelint-disable
|
|
196
|
+
// stylelint-disable selector-max-type -- allow button selector for interactive chips
|
|
200
197
|
button.p-chip--negative {
|
|
201
|
-
// stylelint-disable-next-line selector-max-type
|
|
202
198
|
&:hover {
|
|
203
199
|
background-color: $colors--theme--background-negative-hover;
|
|
204
200
|
border-color: $colors--theme--border-negative;
|
|
205
201
|
}
|
|
206
202
|
|
|
207
|
-
// stylelint-disable-next-line selector-max-type
|
|
208
203
|
&[aria-pressed='true'],
|
|
209
204
|
&.is-selected,
|
|
210
205
|
&:active {
|
|
@@ -212,6 +207,7 @@ $chip-border-thickness: 1px;
|
|
|
212
207
|
border-color: $colors--theme--border-negative;
|
|
213
208
|
}
|
|
214
209
|
}
|
|
210
|
+
// stylelint-enable selector-max-type
|
|
215
211
|
|
|
216
212
|
.p-chip--negative .p-chip__dismiss {
|
|
217
213
|
@include vf-button-pattern(
|
|
@@ -234,15 +230,13 @@ $chip-border-thickness: 1px;
|
|
|
234
230
|
border-color: $colors--theme--border-information;
|
|
235
231
|
}
|
|
236
232
|
|
|
237
|
-
// stylelint-disable
|
|
233
|
+
// stylelint-disable selector-max-type -- allow button selector for interactive chips
|
|
238
234
|
button.p-chip--information {
|
|
239
|
-
// stylelint-disable-next-line selector-max-type
|
|
240
235
|
&:hover {
|
|
241
236
|
background-color: $colors--theme--background-information-hover;
|
|
242
237
|
border-color: $colors--theme--border-information;
|
|
243
238
|
}
|
|
244
239
|
|
|
245
|
-
// stylelint-disable-next-line selector-max-type
|
|
246
240
|
&[aria-pressed='true'],
|
|
247
241
|
&.is-selected,
|
|
248
242
|
&:active {
|
|
@@ -250,6 +244,7 @@ $chip-border-thickness: 1px;
|
|
|
250
244
|
border-color: $colors--theme--border-information;
|
|
251
245
|
}
|
|
252
246
|
}
|
|
247
|
+
// stylelint-enable selector-max-type
|
|
253
248
|
|
|
254
249
|
.p-chip--information .p-chip__dismiss {
|
|
255
250
|
@include vf-button-pattern(
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
@import 'settings';
|
|
2
|
+
|
|
3
|
+
@mixin vf-p-equal-height-row {
|
|
4
|
+
.p-equal-height-row {
|
|
5
|
+
@extend %vf-row;
|
|
6
|
+
position: relative;
|
|
7
|
+
|
|
8
|
+
.p-equal-height-row__col {
|
|
9
|
+
// smaller screens each column will have border top by default
|
|
10
|
+
border-top-color: $colors--theme--border-low-contrast;
|
|
11
|
+
border-top-style: solid;
|
|
12
|
+
border-top-width: 1px;
|
|
13
|
+
display: grid;
|
|
14
|
+
grid-column: span $grid-columns-small;
|
|
15
|
+
grid-row: span 4;
|
|
16
|
+
grid-template-rows: subgrid;
|
|
17
|
+
margin-bottom: $spv--small;
|
|
18
|
+
margin-top: -1px;
|
|
19
|
+
position: relative;
|
|
20
|
+
|
|
21
|
+
@media screen and ($breakpoint-small <= width < $breakpoint-large) {
|
|
22
|
+
grid-column: span $grid-columns-medium;
|
|
23
|
+
grid-template-columns: subgrid;
|
|
24
|
+
|
|
25
|
+
// for medium screen, each column item will take half of the available cols from the parent grid
|
|
26
|
+
.p-equal-height-row__item {
|
|
27
|
+
grid-column: span calc($grid-columns-medium / 2);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// for medium screen, position the first column item on the left of the grid
|
|
31
|
+
.p-equal-height-row__item:first-child {
|
|
32
|
+
grid-row: span 100; // this needs to be sufficiently large so remaining column items won't get stretched
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@media screen and (width >= $breakpoint-large) {
|
|
37
|
+
border: none;
|
|
38
|
+
grid-column: span calc($grid-columns / 4);
|
|
39
|
+
margin-bottom: 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// DIVIDERS
|
|
44
|
+
|
|
45
|
+
// For each row or column grid we only have access to two pseudo elements
|
|
46
|
+
// if 1st-divider (::before) is present, assume 2nd-divider (::after) isn't, then 3rd-divider must be (::after)
|
|
47
|
+
// if 2nd-divider (::after) is present, assume 1st-divider (::before) isn't, then 3rd-divider must be (::before)
|
|
48
|
+
&.has-divider-1::before,
|
|
49
|
+
&.has-divider-2::after,
|
|
50
|
+
&.has-divider-3:not(.has-divider-1)::before,
|
|
51
|
+
&.has-divider-3:not(.has-divider-2)::after {
|
|
52
|
+
// row level dividers are not visible on smaller screen sizes
|
|
53
|
+
@extend %vf-pseudo-border;
|
|
54
|
+
background-color: $colors--theme--border-low-contrast; // override border color to be low contrast
|
|
55
|
+
display: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@media screen and (width >= $breakpoint-large) {
|
|
59
|
+
&.has-divider-1::before,
|
|
60
|
+
&.has-divider-2::after,
|
|
61
|
+
&.has-divider-3:not(.has-divider-1)::before,
|
|
62
|
+
&.has-divider-3:not(.has-divider-2)::after {
|
|
63
|
+
display: block;
|
|
64
|
+
grid-column-end: span 12;
|
|
65
|
+
grid-column-start: 1;
|
|
66
|
+
margin: auto;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&.has-divider-1::before {
|
|
70
|
+
grid-row: 2;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&.has-divider-2::after {
|
|
74
|
+
grid-row: 3;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// when 3rd-divider is present and 1st-divider is not present
|
|
78
|
+
&.has-divider-3:not(.has-divider-1)::before,
|
|
79
|
+
// when 3rd-divider is present and 2nd-divider is not present
|
|
80
|
+
&.has-divider-3:not(.has-divider-2)::after,
|
|
81
|
+
// when only 3rd-divider is present
|
|
82
|
+
&.has-divider-3:not(.has-divider-1):not(.has-divider-2)::before {
|
|
83
|
+
grid-row: 4;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&.has-divider-3:not(.has-divider-1):not(.has-divider-2)::after {
|
|
87
|
+
display: none;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// support for 25-75 split on large screen size for this pattern
|
|
93
|
+
.row--25-75-on-large > .col,
|
|
94
|
+
.row > .col-9 {
|
|
95
|
+
& .p-equal-height-row {
|
|
96
|
+
grid-template-columns: repeat($grid-columns-small, minmax(0, 1fr));
|
|
97
|
+
|
|
98
|
+
@media screen and ($breakpoint-small <= width < $breakpoint-large) {
|
|
99
|
+
grid-template-columns: repeat($grid-columns-medium, minmax(0, 1fr));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@media screen and (width >= $breakpoint-large) {
|
|
103
|
+
grid-template-columns: repeat(9, minmax(0, 1fr));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|