peek-carousel 1.0.2

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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +238 -0
  3. package/README.md +234 -0
  4. package/dist/peek-carousel.css +1 -0
  5. package/dist/peek-carousel.esm.js +1368 -0
  6. package/dist/peek-carousel.esm.js.map +1 -0
  7. package/dist/peek-carousel.esm.min.js +8 -0
  8. package/dist/peek-carousel.esm.min.js.map +1 -0
  9. package/dist/peek-carousel.js +1376 -0
  10. package/dist/peek-carousel.js.map +1 -0
  11. package/dist/peek-carousel.min.css +1 -0
  12. package/dist/peek-carousel.min.js +8 -0
  13. package/dist/peek-carousel.min.js.map +1 -0
  14. package/examples/example-built.html +367 -0
  15. package/examples/example.css +2216 -0
  16. package/examples/example.js +404 -0
  17. package/examples/example.min.css +1 -0
  18. package/examples/example.min.js +1 -0
  19. package/package.json +92 -0
  20. package/src/core/PeekCarousel.js +294 -0
  21. package/src/core/config.js +49 -0
  22. package/src/core/constants.js +73 -0
  23. package/src/modules/Animator.js +244 -0
  24. package/src/modules/AutoRotate.js +43 -0
  25. package/src/modules/EventHandler.js +390 -0
  26. package/src/modules/Navigator.js +116 -0
  27. package/src/modules/UIManager.js +170 -0
  28. package/src/peek-carousel.d.ts +34 -0
  29. package/src/styles/base/_accessibility.scss +16 -0
  30. package/src/styles/base/_mixins.scss +7 -0
  31. package/src/styles/base/_variables.scss +75 -0
  32. package/src/styles/components/_carousel.scss +5 -0
  33. package/src/styles/components/_counter.scss +109 -0
  34. package/src/styles/components/_indicators.scss +154 -0
  35. package/src/styles/components/_navigation.scss +193 -0
  36. package/src/styles/components/carousel/_carousel-base.scss +99 -0
  37. package/src/styles/components/carousel/_carousel-classic.scss +76 -0
  38. package/src/styles/components/carousel/_carousel-mixins.scss +18 -0
  39. package/src/styles/components/carousel/_carousel-radial.scss +72 -0
  40. package/src/styles/components/carousel/_carousel-stack.scss +84 -0
  41. package/src/styles/components/carousel/_carousel-variables.scss +118 -0
  42. package/src/styles/peek-carousel.scss +11 -0
  43. package/src/utils/dom.js +53 -0
  44. package/src/utils/helpers.js +46 -0
  45. package/src/utils/icons.js +92 -0
  46. package/src/utils/preloader.js +69 -0
  47. package/types/index.d.ts +34 -0
@@ -0,0 +1,16 @@
1
+ @use 'variables' as *;
2
+ @use 'sass:color';
3
+ @use 'sass:map';
4
+
5
+ $focus-config: (
6
+ outline-width: 3px,
7
+ outline-offset: 8px,
8
+ outline-alpha: 0.8
9
+ );
10
+
11
+ .peek-carousel__item:focus-visible {
12
+ outline: map.get($focus-config, outline-width) solid
13
+ color.change($color-primary, $alpha: map.get($focus-config, outline-alpha));
14
+ outline-offset: map.get($focus-config, outline-offset);
15
+ border-radius: $radius-lg;
16
+ }
@@ -0,0 +1,7 @@
1
+ @use 'variables' as *;
2
+
3
+ @mixin glassmorphism($bg-color, $blur, $border-color) {
4
+ background: $bg-color;
5
+ backdrop-filter: blur($blur);
6
+ border: 1px solid $border-color;
7
+ }
@@ -0,0 +1,75 @@
1
+ @use 'sass:math';
2
+ @use 'sass:color';
3
+
4
+ $color-white: white;
5
+ $color-black: black;
6
+ $color-primary: rgb(102, 126, 234);
7
+ $color-secondary-base: rgb(118, 75, 162);
8
+
9
+ $color-white-95: color.change($color-white, $alpha: 0.95);
10
+ $color-white-90: color.change($color-white, $alpha: 0.9);
11
+ $color-white-70: color.change($color-white, $alpha: 0.7);
12
+ $color-white-60: color.change($color-white, $alpha: 0.6);
13
+ $color-white-40: color.change($color-white, $alpha: 0.4);
14
+ $color-white-30: color.change($color-white, $alpha: 0.3);
15
+ $color-white-20: color.change($color-white, $alpha: 0.2);
16
+ $color-white-15: color.change($color-white, $alpha: 0.15);
17
+ $color-white-10: color.change($color-white, $alpha: 0.1);
18
+
19
+ $color-black-80: color.change($color-black, $alpha: 0.8);
20
+ $color-black-60: color.change($color-black, $alpha: 0.6);
21
+ $color-black-50: color.change($color-black, $alpha: 0.5);
22
+ $color-black-40: color.change($color-black, $alpha: 0.4);
23
+ $color-black-30: color.change($color-black, $alpha: 0.3);
24
+
25
+ $color-primary-80: color.change($color-primary, $alpha: 0.8);
26
+ $color-primary-60: color.change($color-primary, $alpha: 0.6);
27
+ $color-primary-40: color.change($color-primary, $alpha: 0.4);
28
+ $color-primary-30: color.change($color-primary, $alpha: 0.3);
29
+
30
+ $color-secondary: color.change($color-secondary-base, $alpha: 0.3);
31
+
32
+ $spacing-xs: 0.25rem;
33
+ $spacing-sm: 0.5rem;
34
+ $spacing-md: 0.75rem;
35
+ $spacing-lg: 1rem;
36
+ $spacing-xl: 1.25rem;
37
+ $spacing-2xl: 1.5rem;
38
+ $spacing-3xl: 2rem;
39
+
40
+ $radius-sm: 4px;
41
+ $radius-md: 6px;
42
+ $radius-lg: 12px;
43
+ $radius-xl: 16px;
44
+ $radius-full: 50px;
45
+ $radius-circle: 50%;
46
+
47
+ $transition-fast: 0.15s ease-out;
48
+ $transition-base: 0.3s ease;
49
+ $transition-smooth: 0.5s cubic-bezier(0.4, 0, 0.2, 1);
50
+ $transition-slow: 0.4s cubic-bezier(0.4, 0, 0.2, 1);
51
+
52
+ $shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.2);
53
+ $shadow-md: 0 5px 15px rgba(0, 0, 0, 0.4);
54
+ $shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.6);
55
+ $shadow-glow: 0 2px 8px rgba(255, 255, 255, 0.3), 0 0 12px rgba(255, 255, 255, 0.2);
56
+ $shadow-glow-strong: 0 2px 12px rgba(255, 255, 255, 0.4), 0 0 16px rgba(255, 255, 255, 0.3);
57
+
58
+ $carousel-item-width: clamp(300px, 35vw, 500px);
59
+ $carousel-item-ratio: math.div(650, 490);
60
+ $carousel-blur: 12px;
61
+
62
+ $indicator-size: 10px;
63
+ $indicator-gap: 0.875rem;
64
+ $indicator-active-width: 50px;
65
+ $indicator-active-height: 8px;
66
+
67
+ $nav-btn-size: 36px;
68
+ $nav-btn-size-mobile: 36px;
69
+ $auto-rotate-btn-size: 36px;
70
+
71
+ $z-index-base: 0;
72
+ $z-index-item: 50;
73
+ $z-index-active: 100;
74
+ $z-index-controls: 100;
75
+ $z-index-zoom: 130;
@@ -0,0 +1,5 @@
1
+ @forward 'carousel/carousel-base';
2
+ @forward 'carousel/carousel-stack';
3
+ @forward 'carousel/carousel-radial';
4
+ @forward 'carousel/carousel-classic';
5
+
@@ -0,0 +1,109 @@
1
+ @use '../base/variables' as *;
2
+ @use '../base/mixins' as *;
3
+ @use 'sass:map';
4
+ @use 'sass:color';
5
+
6
+ $counter-config: (
7
+ default: (
8
+ top: 3%,
9
+ left: 3%,
10
+ padding: (0.5rem 1rem),
11
+ font-size: 0.875rem,
12
+ border-radius: 20px
13
+ ),
14
+ mobile: (
15
+ top: 2%,
16
+ left: 2%,
17
+ padding: (0.4rem 0.8rem),
18
+ font-size: 0.75rem
19
+ )
20
+ );
21
+
22
+ $counter-animation: (
23
+ duration: 0.6s,
24
+ easing: cubic-bezier(0.4, 0, 0.2, 1),
25
+ delay: 0.7s,
26
+ translate-y: -10px
27
+ );
28
+
29
+ $counter-styles: (
30
+ bg: color.change($color-black, $alpha: 0.5),
31
+ border: color.change(white, $alpha: 0.15),
32
+ blur: 10px,
33
+ color: white,
34
+ font-weight: 500,
35
+ z-index: 100
36
+ );
37
+
38
+ $counter-elements: (
39
+ separator: (
40
+ margin: (0 0.25rem),
41
+ opacity: 0.7
42
+ ),
43
+ current: (
44
+ font-weight: 600
45
+ ),
46
+ total: (
47
+ opacity: 0.8
48
+ )
49
+ );
50
+
51
+
52
+ @mixin counter-layout($config) {
53
+ position: absolute;
54
+ inset: map.get($config, top) auto auto map.get($config, left);
55
+ padding: map.get($config, padding);
56
+ font-size: map.get($config, font-size);
57
+ }
58
+
59
+ .peek-carousel__counter {
60
+ $default: map.get($counter-config, default);
61
+
62
+ @include counter-layout($default);
63
+ @include glassmorphism(
64
+ map.get($counter-styles, bg),
65
+ map.get($counter-styles, blur),
66
+ map.get($counter-styles, border)
67
+ );
68
+
69
+ z-index: map.get($counter-styles, z-index);
70
+ border-radius: map.get($default, border-radius);
71
+ color: map.get($counter-styles, color);
72
+ font-weight: map.get($counter-styles, font-weight);
73
+ line-height: 1;
74
+ user-select: none;
75
+ pointer-events: none;
76
+ opacity: 0;
77
+ transform: translateY(map.get($counter-animation, translate-y));
78
+ animation: fadeInDown
79
+ map.get($counter-animation, duration)
80
+ map.get($counter-animation, easing)
81
+ forwards;
82
+ animation-delay: map.get($counter-animation, delay);
83
+
84
+ @media (max-width: 768px) {
85
+ $mobile: map.get($counter-config, mobile);
86
+ @include counter-layout($mobile);
87
+ }
88
+
89
+ &-separator {
90
+ $separator: map.get($counter-elements, separator);
91
+ margin: map.get($separator, margin);
92
+ opacity: map.get($separator, opacity);
93
+ }
94
+
95
+ &-current {
96
+ font-weight: map.get(map.get($counter-elements, current), font-weight);
97
+ }
98
+
99
+ &-total {
100
+ opacity: map.get(map.get($counter-elements, total), opacity);
101
+ }
102
+ }
103
+
104
+ @keyframes fadeInDown {
105
+ to {
106
+ opacity: 1;
107
+ transform: translateY(0);
108
+ }
109
+ }
@@ -0,0 +1,154 @@
1
+ @use '../base/variables' as *;
2
+ @use '../base/mixins' as *;
3
+ @use 'sass:map';
4
+
5
+ $controls-animation: (
6
+ duration: 0.6s,
7
+ easing: cubic-bezier(0.4, 0, 0.2, 1),
8
+ delay: 0.6s,
9
+ translate-y: 20px
10
+ );
11
+
12
+ $indicator-dimensions: (
13
+ default: (
14
+ width: $indicator-size,
15
+ height: $indicator-size
16
+ ),
17
+ active: (
18
+ width: $indicator-active-width,
19
+ height: $indicator-active-height
20
+ )
21
+ );
22
+
23
+ @mixin indicator-dot($width, $height, $bg-color) {
24
+ content: '';
25
+ width: $width;
26
+ height: $height;
27
+ border-radius: if($width == $height, $radius-circle, $radius-full);
28
+ background: $bg-color;
29
+ transition: all $transition-base;
30
+ }
31
+
32
+ .peek-carousel__controls {
33
+ position: absolute;
34
+ inset: auto auto 3% 50%;
35
+ transform: translateX(-50%);
36
+ display: flex;
37
+ align-items: center;
38
+ gap: $spacing-md;
39
+ z-index: $z-index-controls;
40
+ opacity: 0;
41
+ animation: fadeInUpControls
42
+ map.get($controls-animation, duration)
43
+ map.get($controls-animation, easing)
44
+ forwards;
45
+ animation-delay: map.get($controls-animation, delay);
46
+ }
47
+
48
+ .peek-carousel__indicators {
49
+ display: flex;
50
+ align-items: center;
51
+ gap: $indicator-gap;
52
+ padding: 0.625rem $spacing-lg;
53
+ border-radius: $radius-full;
54
+ @include glassmorphism($color-black-50, $carousel-blur, $color-white-15);
55
+ }
56
+
57
+ .peek-carousel__indicator {
58
+ $default: map.get($indicator-dimensions, default);
59
+ $active: map.get($indicator-dimensions, active);
60
+
61
+ width: map.get($default, width);
62
+ height: map.get($default, height);
63
+ border-radius: $radius-circle;
64
+ background: transparent;
65
+ cursor: pointer;
66
+ transition: all $transition-base;
67
+ border: none;
68
+ padding: 0;
69
+ position: relative;
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+
74
+ &::before {
75
+ @include indicator-dot(
76
+ map.get($default, width),
77
+ map.get($default, height),
78
+ $color-white-40
79
+ );
80
+ }
81
+
82
+ &:hover::before {
83
+ background: $color-white-60;
84
+ transform: scale(1.2);
85
+ }
86
+
87
+ &--active {
88
+ width: map.get($active, width);
89
+ overflow: hidden;
90
+ border-radius: $radius-full;
91
+
92
+ &::before {
93
+ @include indicator-dot(
94
+ map.get($active, width),
95
+ map.get($active, height),
96
+ $color-white-30
97
+ );
98
+ }
99
+
100
+ &::after {
101
+ @include indicator-dot(
102
+ map.get($active, width),
103
+ map.get($active, height),
104
+ $color-white-95
105
+ );
106
+ position: absolute;
107
+ inset: 50% auto auto 0;
108
+ transform: translateY(-50%);
109
+ box-shadow: $shadow-glow;
110
+ }
111
+
112
+ &:hover {
113
+ &::before {
114
+ background: $color-white-40;
115
+ }
116
+
117
+ &::after {
118
+ background: $color-white;
119
+ box-shadow: $shadow-glow-strong;
120
+ }
121
+ }
122
+
123
+ &.peek-carousel__indicator--progress::after {
124
+ width: 0;
125
+ animation: indicatorProgress linear forwards;
126
+ animation-duration: var(--progress-duration, 2500ms);
127
+ }
128
+ }
129
+
130
+ &--completed::after {
131
+ width: map.get($active, width) !important;
132
+ animation: none;
133
+ }
134
+ }
135
+
136
+ @keyframes fadeInUpControls {
137
+ from {
138
+ opacity: 0;
139
+ transform: translateX(-50%) translateY(map.get($controls-animation, translate-y));
140
+ }
141
+ to {
142
+ opacity: 1;
143
+ transform: translateX(-50%) translateY(0);
144
+ }
145
+ }
146
+
147
+ @keyframes indicatorProgress {
148
+ from {
149
+ width: 0;
150
+ }
151
+ to {
152
+ width: map.get(map.get($indicator-dimensions, active), width);
153
+ }
154
+ }
@@ -0,0 +1,193 @@
1
+ @use '../base/variables' as *;
2
+ @use '../base/mixins' as *;
3
+ @use 'sass:map';
4
+
5
+ $nav-animation: (
6
+ duration: 0.6s,
7
+ easing: cubic-bezier(0.4, 0, 0.2, 1),
8
+ delay: 0.5s,
9
+ translate-y: 20px
10
+ );
11
+
12
+ $button-config: (
13
+ nav: (
14
+ size: $nav-btn-size,
15
+ size-mobile: $nav-btn-size-mobile,
16
+ bg: $color-white-10,
17
+ bg-hover: $color-white-20,
18
+ border: $color-white-20,
19
+ blur: 10px
20
+ ),
21
+ auto-rotate: (
22
+ size: $auto-rotate-btn-size,
23
+ bg: $color-black-50,
24
+ bg-hover: $color-black-60,
25
+ bg-active: $color-white-20,
26
+ border: $color-white-15,
27
+ border-hover: $color-white-30,
28
+ blur: $carousel-blur
29
+ )
30
+ );
31
+
32
+ $icon-states: (
33
+ default: (
34
+ play: block,
35
+ pause: none
36
+ ),
37
+ active: (
38
+ play: none,
39
+ pause: block
40
+ )
41
+ );
42
+
43
+ $transforms: (
44
+ hover-scale: 1.1,
45
+ active-scale: 0.95,
46
+ nudge-distance: 2px
47
+ );
48
+
49
+
50
+ @mixin button-base($size, $bg, $border, $blur) {
51
+ width: $size;
52
+ height: $size;
53
+ border-radius: $radius-circle;
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ cursor: pointer;
58
+ transition: all $transition-base;
59
+ user-select: none;
60
+ @include glassmorphism($bg, $blur, $border);
61
+ }
62
+
63
+ @mixin interactive-states($bg-hover, $border-hover: null) {
64
+ &:hover {
65
+ background: $bg-hover;
66
+ transform: scale(map.get($transforms, hover-scale));
67
+
68
+ @if $border-hover {
69
+ border-color: $border-hover;
70
+ }
71
+ }
72
+
73
+ &:active {
74
+ transform: scale(map.get($transforms, active-scale));
75
+ }
76
+
77
+ &:focus-visible {
78
+ outline: 3px solid $color-primary-80;
79
+ outline-offset: 4px;
80
+ }
81
+ }
82
+
83
+ @mixin icon-visibility($state) {
84
+ .play-icon {
85
+ display: map.get(map.get($icon-states, $state), play);
86
+ }
87
+
88
+ .pause-icon {
89
+ display: map.get(map.get($icon-states, $state), pause);
90
+ }
91
+ }
92
+
93
+ .peek-carousel__nav {
94
+ position: absolute;
95
+ inset: auto auto 8% 50%;
96
+ transform: translateX(-50%);
97
+ display: flex;
98
+ gap: $spacing-3xl;
99
+ z-index: $z-index-controls;
100
+ align-items: center;
101
+ opacity: 0;
102
+ animation: fadeInUpNav
103
+ map.get($nav-animation, duration)
104
+ map.get($nav-animation, easing)
105
+ forwards;
106
+ animation-delay: map.get($nav-animation, delay);
107
+
108
+ @media (max-width: 768px) {
109
+ bottom: 12%;
110
+ }
111
+ }
112
+
113
+ .peek-carousel__btn {
114
+ $nav-config: map.get($button-config, nav);
115
+
116
+ @include button-base(
117
+ map.get($nav-config, size),
118
+ map.get($nav-config, bg),
119
+ map.get($nav-config, border),
120
+ map.get($nav-config, blur)
121
+ );
122
+
123
+ color: white;
124
+ font-size: 1rem;
125
+ place-items: center;
126
+ display: grid;
127
+
128
+ svg {
129
+ width: 18px;
130
+ height: 18px;
131
+ flex-shrink: 0;
132
+ transition: transform $transition-fast;
133
+ }
134
+
135
+ @include interactive-states(map.get($nav-config, bg-hover));
136
+
137
+ &:hover svg {
138
+ transform: translateX(0);
139
+ }
140
+
141
+ &.prev-btn:hover svg {
142
+ transform: translateX(calc(-1 * map.get($transforms, nudge-distance)));
143
+ }
144
+
145
+ &.next-btn:hover svg {
146
+ transform: translateX(map.get($transforms, nudge-distance));
147
+ }
148
+
149
+ @media (max-width: 768px) {
150
+ width: map.get($nav-config, size-mobile);
151
+ height: map.get($nav-config, size-mobile);
152
+ }
153
+
154
+ &--auto-rotate {
155
+ $rotate-config: map.get($button-config, auto-rotate);
156
+
157
+ @include button-base(
158
+ map.get($rotate-config, size),
159
+ map.get($rotate-config, bg),
160
+ map.get($rotate-config, border),
161
+ map.get($rotate-config, blur)
162
+ );
163
+
164
+ padding: 0;
165
+
166
+ svg {
167
+ flex-shrink: 0;
168
+ }
169
+
170
+ @include icon-visibility(default);
171
+ @include interactive-states(
172
+ map.get($rotate-config, bg-hover),
173
+ map.get($rotate-config, border-hover)
174
+ );
175
+
176
+ &.peek-carousel__btn--active {
177
+ background: map.get($rotate-config, bg-active);
178
+ border-color: map.get($rotate-config, border-hover);
179
+ @include icon-visibility(active);
180
+ }
181
+ }
182
+ }
183
+
184
+ @keyframes fadeInUpNav {
185
+ from {
186
+ opacity: 0;
187
+ transform: translateX(-50%) translateY(map.get($nav-animation, translate-y));
188
+ }
189
+ to {
190
+ opacity: 1;
191
+ transform: translateX(-50%) translateY(0);
192
+ }
193
+ }
@@ -0,0 +1,99 @@
1
+ @use '../../base/variables' as *;
2
+ @use 'carousel-variables' as *;
3
+ @use 'sass:list';
4
+
5
+ .peek-carousel {
6
+ position: relative;
7
+ width: 100%;
8
+ height: 100%;
9
+ display: grid;
10
+ place-items: center;
11
+ user-select: none;
12
+ cursor: grab;
13
+
14
+ opacity: 0;
15
+ transform: translateY($initial-offset);
16
+ animation: fadeInUp $animation-duration cubic-bezier(0.4, 0, 0.2, 1) forwards;
17
+ animation-delay: $animation-delay;
18
+
19
+ --drag-offset: 0px;
20
+ --drag-rotation: 0deg;
21
+ --drag-rotation-y: 0deg;
22
+
23
+ &__track {
24
+ position: relative;
25
+ width: 100%;
26
+ height: 100%;
27
+ touch-action: pan-y;
28
+ transform-style: preserve-3d;
29
+ }
30
+
31
+ &__item {
32
+ position: absolute;
33
+ top: 50%;
34
+ left: 50%;
35
+ width: $carousel-item-width;
36
+ aspect-ratio: $carousel-item-ratio;
37
+ transform-origin: center;
38
+ will-change: transform, opacity;
39
+ backface-visibility: hidden;
40
+ transform: translate(-50%, -50%) scale($item-default-scale);
41
+ z-index: $z-index-base;
42
+
43
+ --item-x: 0%;
44
+ --item-scale: #{$item-default-scale};
45
+ --item-offset-x: 0px;
46
+ --item-angle: 0deg;
47
+ --item-radius: #{$item-default-radius};
48
+
49
+ &--active {
50
+ .peek-carousel__caption {
51
+ opacity: 1;
52
+ }
53
+ }
54
+
55
+ @media (max-width: $breakpoint-mobile) {
56
+ width: clamp($item-mobile-min-width, 80vw, $item-mobile-max-width);
57
+ --item-radius: #{$item-mobile-radius};
58
+ }
59
+ }
60
+
61
+ &__figure {
62
+ margin: 0;
63
+ position: relative;
64
+ width: 100%;
65
+ height: 100%;
66
+ }
67
+
68
+ &__image {
69
+ width: 100%;
70
+ height: 100%;
71
+ object-fit: cover;
72
+ border-radius: $radius-xl;
73
+ box-shadow: list.join($shadow-lg, $shadow-md, $separator: comma);
74
+ transition:
75
+ filter $transition-slow,
76
+ box-shadow $transition-slow;
77
+ will-change: filter, box-shadow;
78
+ }
79
+
80
+ &__caption {
81
+ position: absolute;
82
+ inset: auto 0 0;
83
+ color: white;
84
+ text-align: center;
85
+ padding: $spacing-2xl;
86
+ background: linear-gradient(to top, $color-black-80, transparent);
87
+ border-radius: 0 0 $radius-xl $radius-xl;
88
+ opacity: 0;
89
+ transition: opacity $transition-base;
90
+ pointer-events: none;
91
+ }
92
+ }
93
+
94
+ @keyframes fadeInUp {
95
+ to {
96
+ opacity: 1;
97
+ transform: translateY(0);
98
+ }
99
+ }