@webitel/ui-sdk 26.2.126 → 26.2.127

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 (62) hide show
  1. package/dist/{index-Cz4qFQN1.js → index-BUTu9WZ2.js} +1 -1
  2. package/dist/{index-qLMzWnx2.js → index-BwJPAF-L.js} +1 -1
  3. package/dist/{install-In0YqDcO.js → install-CZVo_Lgq.js} +34 -34
  4. package/dist/{isObject-DN6MD8kE.js → isObject-D8NbLIvn.js} +1 -1
  5. package/dist/ui-sdk.css +1 -1
  6. package/dist/ui-sdk.js +1 -1
  7. package/dist/ui-sdk.umd.cjs +227 -227
  8. package/dist/useVidstackSrc-By2DvVYE.js +1341 -0
  9. package/dist/{vidstack-Bq6c3Bam-CJx1I67B.js → vidstack-Bq6c3Bam-DZpVUP6u.js} +21 -20
  10. package/dist/{vidstack-D2pY00kU-BzDVmOQf.js → vidstack-D2pY00kU-DmzmbaxA.js} +12 -11
  11. package/dist/{vidstack-DDXt6fpN-CccMyx3k.js → vidstack-DDXt6fpN-R-RL7xbd.js} +10 -9
  12. package/dist/{vidstack-D_-9AA6_-Ch_AQKf8.js → vidstack-D_-9AA6_-Rtg1rWZn.js} +6 -5
  13. package/dist/{vidstack-DqAw8m9J-DN0Rx2Cp.js → vidstack-DqAw8m9J-CKBPiM-T.js} +1 -1
  14. package/dist/{vidstack-audio-CyicYFtE.js → vidstack-audio-BSa_ocPo.js} +2 -2
  15. package/dist/{vidstack-dash-BbVUAfel.js → vidstack-dash-B6zBTqpJ.js} +25 -24
  16. package/dist/{vidstack-google-cast-BxNHua_2.js → vidstack-google-cast-BiVGBXq7.js} +12 -11
  17. package/dist/{vidstack-hls-ok-wSuoG.js → vidstack-hls-wBjg7Hh4.js} +24 -23
  18. package/dist/{vidstack-video-CaJH1npJ.js → vidstack-video-ClLmD1ZH.js} +16 -15
  19. package/dist/{vidstack-vimeo-OTNo1lZl.js → vidstack-vimeo-DS-QbjIw.js} +37 -36
  20. package/dist/{vidstack-youtube-TJnLoStb.js → vidstack-youtube-qgcRlwA4.js} +15 -14
  21. package/dist/{wt-action-bar-DVYTKUBk.js → wt-action-bar-7OiuP0SB.js} +1 -1
  22. package/dist/{wt-button-select-CDYL61lk.js → wt-button-select-DLhgqiNm.js} +1 -1
  23. package/dist/{wt-chat-emoji-CzXGoTsc.js → wt-chat-emoji-x6meRlHK.js} +2 -2
  24. package/dist/{wt-confirm-dialog-Cw3PoxjN.js → wt-confirm-dialog-B5acXgBg.js} +1 -1
  25. package/dist/{wt-context-menu-DIkv1NaC.js → wt-context-menu-C0ojSpj9.js} +1 -1
  26. package/dist/{wt-copy-action-C_Lp0i_H.js → wt-copy-action-BHtpbM1D.js} +1 -1
  27. package/dist/{wt-datepicker-DnMpx5eZ.js → wt-datepicker-B-DkCLJn.js} +1 -1
  28. package/dist/{wt-display-chip-items-ZeT2D9at.js → wt-display-chip-items-DJ1weT-w.js} +1 -1
  29. package/dist/{wt-dual-panel-6RTh5YbZ.js → wt-dual-panel-D0ZnkPsk.js} +1 -1
  30. package/dist/{wt-dummy-Cj90QXzn.js → wt-dummy-THJSxLe-.js} +1 -1
  31. package/dist/{wt-error-page-xX2SEe3s.js → wt-error-page-CDEW8r7j.js} +1 -1
  32. package/dist/{wt-expansion-card-BjdYf5Dp.js → wt-expansion-card-BAShSfNt.js} +1 -1
  33. package/dist/{wt-expansion-panel-DK0SYvoG.js → wt-expansion-panel-UY2XN6T-.js} +1 -1
  34. package/dist/{wt-filters-panel-wrapper-OApRf81V.js → wt-filters-panel-wrapper-U39Z2PjA.js} +1 -1
  35. package/dist/{wt-galleria-rRQcZ_0y.js → wt-galleria-CmKffAlW.js} +1 -1
  36. package/dist/{wt-navigation-menu-C-nB-8Le.js → wt-navigation-menu-az7Y3Fmv.js} +1 -1
  37. package/dist/{wt-notifications-bar-D1i5rV8A.js → wt-notifications-bar-B0-JXCXS.js} +2 -2
  38. package/dist/{wt-pagination-C59kdDDN.js → wt-pagination-DkX3-gKr.js} +1 -1
  39. package/dist/wt-player-prneqTCR.js +128 -0
  40. package/dist/{wt-search-bar-C4-Vl9Pa.js → wt-search-bar-CvGFew1I.js} +1 -1
  41. package/dist/{wt-selection-popup-BxDERIHb.js → wt-selection-popup-BCI218Os.js} +1 -1
  42. package/dist/{wt-start-page-BPlJho8Y.js → wt-start-page-bzDQWjgT.js} +1 -1
  43. package/dist/{wt-status-select-CNH5kFvr.js → wt-status-select-CErY8L3f.js} +1 -1
  44. package/dist/{wt-stepper-1_iQtsZC.js → wt-stepper-CKG4zjhT.js} +1 -1
  45. package/dist/{wt-table-D76yjtwy.js → wt-table-DoCH9Fm0.js} +1 -1
  46. package/dist/{wt-table-actions-DodTkdCV.js → wt-table-actions-Ctup80uD.js} +1 -1
  47. package/dist/{wt-table-column-select-VKKAj8Ox.js → wt-table-column-select-BWAndHnT.js} +2 -2
  48. package/dist/{wt-tabs-DyO6wmnS.js → wt-tabs-u3PJupFN.js} +1 -1
  49. package/dist/{wt-tags-input-BucUo4Ow.js → wt-tags-input-D49e88Tx.js} +2 -2
  50. package/dist/{wt-timepicker-t2uY6aU1.js → wt-timepicker-D0mQNGqO.js} +1 -1
  51. package/dist/{wt-tree-BZI_RN8N.js → wt-tree-DTKz3EvL.js} +2 -2
  52. package/dist/{wt-tree-table-CvtJrEN6.js → wt-tree-table-BK30pMTp.js} +1 -1
  53. package/dist/{wt-type-extension-value-input-BjPJ1FmI.js → wt-type-extension-value-input-BwStDhpW.js} +2 -2
  54. package/dist/{wt-vidstack-player-BB6Gwvf5.js → wt-vidstack-player-BFilvSVA.js} +2800 -4044
  55. package/package.json +1 -1
  56. package/src/components/wt-player/wt-player.vue +7 -24
  57. package/src/components/wt-vidstack-player/composables/useVidstackSrc.ts +111 -0
  58. package/src/components/wt-vidstack-player/wt-vidstack-player.vue +10 -40
  59. package/types/components/wt-vidstack-player/composables/useVidstackSrc.d.ts +27 -0
  60. package/types/components/wt-vidstack-player/wt-vidstack-player.vue.d.ts +2 -4
  61. package/dist/time-group-CkVy2t63.js +0 -25
  62. package/dist/wt-player-CrLSS40S.js +0 -138
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "26.2.126",
3
+ "version": "26.2.127",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "make-all": "npm version patch --git-tag-version false && npm run build && (npm run build:types || true) && (npm run biome:format:all || true) && npm run publish-lib",
@@ -2,7 +2,7 @@
2
2
  <media-player
3
3
  class="wt-player"
4
4
  :class="`wt-player--position-${props.position}`"
5
- :src="normalizedSrc"
5
+ :src="normalizedSrcObject"
6
6
  :loop="props.loop"
7
7
  :autoplay="autoplay"
8
8
  @ended="handleEnded"
@@ -49,10 +49,11 @@
49
49
  lang="ts"
50
50
  >
51
51
  import 'vidstack/bundle';
52
- import type { AudioMimeType, MediaSrc } from 'vidstack';
53
- import { computed, useTemplateRef } from 'vue';
52
+ import type { MediaSrc } from 'vidstack';
53
+ import { computed, toRefs } from 'vue';
54
54
 
55
55
  import TimeGroup from '../wt-vidstack-player/components/panels/playback-controls-panel/components/time-group.vue';
56
+ import { useVidstackSrc } from '../wt-vidstack-player/composables/useVidstackSrc';
56
57
  import MuteButton from './src/components/buttons/mute-button.vue';
57
58
  import PlayButton from './src/components/buttons/play-button.vue';
58
59
  import TimeSlider from './src/components/sliders/time-slider.vue';
@@ -135,31 +136,13 @@ const emit = defineEmits<{
135
136
  initialized: []; // is needed?
136
137
  close: [];
137
138
  }>();
138
- const normalizedSrc = computed(() => {
139
- if (!props.src?.type) return props.src;
140
139
 
141
- const type = handleVidstackUnsupportedAudioTypes(props.src.type);
140
+ const { src: srcRef } = toRefs(props);
142
141
 
143
- return {
144
- src: props.src.src,
145
- type,
146
- };
142
+ const { normalizedSrcObject } = useVidstackSrc({
143
+ src: srcRef,
147
144
  });
148
145
 
149
- /**
150
- * https://webitel.atlassian.net/browse/WTEL-8723?focusedCommentId=733255
151
- * https://github.com/vidstack/player/issues/1453
152
- *
153
- */
154
- function handleVidstackUnsupportedAudioTypes(mimeType: string): AudioMimeType {
155
- const unsupportedTypes = [
156
- 'audio/wav',
157
- ];
158
- return unsupportedTypes.includes(mimeType)
159
- ? 'audio/mp3'
160
- : (mimeType as AudioMimeType);
161
- }
162
-
163
146
  function downloadMedia() {
164
147
  const src = typeof props.src === 'string' ? props.src : props.src?.src;
165
148
 
@@ -0,0 +1,111 @@
1
+ import {
2
+ isAudioSrc as vidstackNativeIsAudioCheck,
3
+ isVideoSrc as vidstackNativeIsVideoCheck,
4
+ } from 'vidstack';
5
+ import { computed, toRef } from 'vue';
6
+
7
+ export const useVidstackSrc = ({ src, type, stream }) => {
8
+ const srcRef = toRef(src);
9
+ const typeRef = toRef(type);
10
+ const streamRef = toRef(stream);
11
+
12
+ const normalizedType = computed(() => {
13
+ if (streamRef.value) return 'video/object';
14
+
15
+ return typeRef.value || srcRef.value?.type;
16
+ });
17
+
18
+ const normalizedSrcValue = computed(() => {
19
+ if (streamRef.value) return streamRef.value;
20
+
21
+ return typeof srcRef.value === 'string' ? srcRef.value : srcRef.value?.src;
22
+ });
23
+
24
+ const normalizedSrcObject = computed(() => {
25
+ return normalizeVidstackMediaSrc({
26
+ src: normalizedSrcValue.value,
27
+ type: normalizedType.value,
28
+ });
29
+ });
30
+
31
+ return {
32
+ normalizedSrcObject,
33
+ };
34
+ };
35
+
36
+ /**
37
+ * https://webitel.atlassian.net/browse/WTEL-8723?focusedCommentId=733255
38
+ * https://github.com/vidstack/player/issues/1453
39
+ *
40
+ * vidstack doesn't recognize some audio/video types as audio/video,
41
+ * so we need to normalize them to default audio/video formats
42
+ *
43
+ * for instance, type: "audio/wav" won't be recognized as audio by vidstack,
44
+ * so we need to fallback it to "audio/mp3"
45
+ */
46
+ export function normalizeVidstackMediaSrc({
47
+ src,
48
+ type,
49
+ }: {
50
+ src: string | unknown; // "string" for url, "unknown" for JS objects like MediaStream or Blob
51
+ type: string;
52
+ }) {
53
+ // if vidstack parses src and type correctly, no need to normalize
54
+ if (
55
+ vidstackNativeIsAudioCheck({
56
+ src,
57
+ type,
58
+ }) ||
59
+ vidstackNativeIsVideoCheck({
60
+ src,
61
+ type,
62
+ })
63
+ ) {
64
+ return {
65
+ src,
66
+ type,
67
+ };
68
+ }
69
+
70
+ // handle "video/object" or "audio/object" types
71
+ if (
72
+ isObjectSrcType({
73
+ src,
74
+ type,
75
+ })
76
+ ) {
77
+ return {
78
+ src,
79
+ type,
80
+ };
81
+ }
82
+
83
+ // normalize to default audio format, if vidstack doesn't recognize this type as audio
84
+ if (type.includes('audio')) {
85
+ return {
86
+ src,
87
+ type: 'audio/mp3',
88
+ };
89
+ }
90
+
91
+ // normalize to default video format, if vidstack doesn't recognize this type as video
92
+ if (type.includes('video')) {
93
+ return {
94
+ src,
95
+ type: 'video/mp4',
96
+ };
97
+ }
98
+
99
+ // unknown. hz, ebites' sami
100
+ return {
101
+ src,
102
+ type,
103
+ };
104
+ }
105
+
106
+ /**
107
+ * "video/object" or "audio/object" types represent JS objects like MediaStream or file Blob
108
+ */
109
+ function isObjectSrcType({ src, type }: { src: unknown; type: string }) {
110
+ return type.includes('/object');
111
+ }
@@ -13,7 +13,7 @@
13
13
  ref="player"
14
14
  :autoplay="props.autoplay"
15
15
  :muted="props.muted"
16
- :src="normalizedSrc"
16
+ :src="normalizedSrcObject"
17
17
  class="wt-vidstack-player__player"
18
18
  cross-origin
19
19
  playsinline
@@ -48,18 +48,15 @@
48
48
  <script lang="ts" setup>
49
49
  import 'vidstack/player';
50
50
  import 'vidstack/player/ui';
51
- import { computed, provide, ref } from 'vue';
51
+ import type { MediaSrc } from 'vidstack';
52
+ import { computed, provide, ref, toRefs } from 'vue';
52
53
 
53
54
  import { ComponentSize } from '../../enums';
54
55
  import { VideoLayout } from './components';
56
+ import { useVidstackSrc } from './composables/useVidstackSrc';
55
57
 
56
58
  interface Props {
57
- src?:
58
- | string
59
- | {
60
- src: string;
61
- type?: string;
62
- };
59
+ src?: MediaSrc;
63
60
  mime?: string;
64
61
  autoplay?: boolean;
65
62
  muted?: boolean;
@@ -114,39 +111,12 @@ provide('size', {
114
111
  changeSize,
115
112
  });
116
113
 
117
- const normalizedType = computed(() => {
118
- // https://vidstack.io/docs/wc/player/core-concepts/loading/?styling=css#source-types
119
- if (props.mime) return props.mime;
114
+ const { src: srcRef, type: typeRef, stream: streamRef } = toRefs(props);
120
115
 
121
- if (typeof props.src === 'string') {
122
- if (props.src.includes('media')) return 'audio/mp3';
123
- if (props.src.includes('mp3')) return 'audio/mp3';
124
- if (props.src.includes('ogg') || props.src.includes('oga'))
125
- return 'audio/ogg';
126
- }
127
-
128
- return 'video/mp4';
129
- });
130
-
131
- const normalizedSrc = computed(() => {
132
- if (props.stream) {
133
- return {
134
- src: props.stream,
135
- type: 'video/object',
136
- };
137
- }
138
-
139
- if (typeof props.src === 'string') {
140
- return {
141
- src: props.src,
142
- type: normalizedType.value,
143
- };
144
- }
145
-
146
- return {
147
- src: props.src?.src || null,
148
- type: props.src?.type || normalizedType.value,
149
- };
116
+ const { normalizedSrcObject } = useVidstackSrc({
117
+ src: srcRef,
118
+ type: typeRef,
119
+ stream: streamRef,
150
120
  });
151
121
 
152
122
  const onCanPlay = (ev: Event) => {
@@ -0,0 +1,27 @@
1
+ export declare const useVidstackSrc: ({ src, type, stream }: {
2
+ src: any;
3
+ type: any;
4
+ stream: any;
5
+ }) => {
6
+ normalizedSrcObject: import("vue").ComputedRef<{
7
+ src: unknown;
8
+ type: string;
9
+ }>;
10
+ };
11
+ /**
12
+ * https://webitel.atlassian.net/browse/WTEL-8723?focusedCommentId=733255
13
+ * https://github.com/vidstack/player/issues/1453
14
+ *
15
+ * vidstack doesn't recognize some audio/video types as audio/video,
16
+ * so we need to normalize them to default audio/video formats
17
+ *
18
+ * for instance, type: "audio/wav" won't be recognized as audio by vidstack,
19
+ * so we need to fallback it to "audio/mp3"
20
+ */
21
+ export declare function normalizeVidstackMediaSrc({ src, type, }: {
22
+ src: string | unknown;
23
+ type: string;
24
+ }): {
25
+ src: unknown;
26
+ type: string;
27
+ };
@@ -1,11 +1,9 @@
1
1
  import 'vidstack/player';
2
2
  import 'vidstack/player/ui';
3
+ import type { MediaSrc } from 'vidstack';
3
4
  import { ComponentSize } from '../../enums';
4
5
  interface Props {
5
- src?: string | {
6
- src: string;
7
- type?: string;
8
- };
6
+ src?: MediaSrc;
9
7
  mime?: string;
10
8
  autoplay?: boolean;
11
9
  muted?: boolean;
@@ -1,25 +0,0 @@
1
- import { defineComponent as p, createElementBlock as t, openBlock as o, Fragment as i, createElementVNode as n, createTextVNode as s } from "vue";
2
- import { _ as d } from "./install-In0YqDcO.js";
3
- const a = { class: "time-group" }, u = {
4
- key: 0,
5
- type: "current",
6
- remainder: ""
7
- }, l = /* @__PURE__ */ p({
8
- __name: "time-group",
9
- props: {
10
- countdown: { type: Boolean, default: !1 }
11
- },
12
- setup(r) {
13
- const m = r;
14
- return (c, e) => (o(), t("div", a, [
15
- m.countdown ? (o(), t("media-time", u)) : (o(), t(i, { key: 1 }, [
16
- e[0] || (e[0] = n("media-time", { type: "current" }, null, -1)),
17
- e[1] || (e[1] = s(" / ", -1)),
18
- e[2] || (e[2] = n("media-time", { type: "duration" }, null, -1))
19
- ], 64))
20
- ]));
21
- }
22
- }), y = /* @__PURE__ */ d(l, [["__scopeId", "data-v-c80a48e6"]]);
23
- export {
24
- y as T
25
- };
@@ -1,138 +0,0 @@
1
- import { resolveComponent as f, createElementBlock as a, openBlock as l, createVNode as o, defineComponent as u, computed as k, normalizeClass as B, createElementVNode as _, createBlock as z, createCommentVNode as p } from "vue";
2
- import { T as C } from "./time-group-CkVy2t63.js";
3
- import { _ as r, E as y } from "./install-In0YqDcO.js";
4
- import { _ as w } from "./wt-slider.vue_vue_type_script_setup_true_lang-DlaRDHxo.js";
5
- const E = {}, T = { class: "mute-button" };
6
- function x(s, d) {
7
- const e = f("wt-icon");
8
- return l(), a("media-mute-button", T, [
9
- o(e, {
10
- type: "mute",
11
- icon: "plyr-muted",
12
- class: "mute-icon",
13
- size: "sm"
14
- }),
15
- o(e, {
16
- type: "volume",
17
- icon: "plyr-volume",
18
- class: "volume-icon",
19
- size: "sm"
20
- })
21
- ]);
22
- }
23
- const V = /* @__PURE__ */ r(E, [["render", x], ["__scopeId", "data-v-8394e2c8"]]), S = { class: "play-button" }, g = /* @__PURE__ */ u({
24
- __name: "play-button",
25
- setup(s) {
26
- return (d, e) => (l(), a("media-play-button", S, [
27
- o(y, {
28
- icon: "plyr-play",
29
- type: "play",
30
- class: "play-icon",
31
- size: "sm"
32
- }),
33
- o(y, {
34
- icon: "plyr-pause",
35
- type: "pause",
36
- class: "pause-icon",
37
- size: "sm"
38
- })
39
- ]));
40
- }
41
- }), I = /* @__PURE__ */ r(g, [["__scopeId", "data-v-e79e3bf5"]]), M = { class: "time-slider media-slider" }, N = /* @__PURE__ */ u({
42
- __name: "time-slider",
43
- setup(s) {
44
- return (d, e) => (l(), a("media-time-slider", M, [
45
- o(w, { class: "time-slider__slider" })
46
- ]));
47
- }
48
- }), O = /* @__PURE__ */ r(N, [["__scopeId", "data-v-e57a9871"]]), P = { class: "volume-slider media-slider" }, A = /* @__PURE__ */ u({
49
- __name: "volume-slider",
50
- setup(s) {
51
- return (d, e) => (l(), a("media-volume-slider", P, [
52
- o(w, { class: "volume-slider__slider" })
53
- ]));
54
- }
55
- }), F = /* @__PURE__ */ r(A, [["__scopeId", "data-v-b92a4daf"]]), G = ["src", "loop", "autoplay"], U = { class: "controls-group" }, j = /* @__PURE__ */ u({
56
- __name: "wt-player",
57
- props: {
58
- src: {},
59
- id: {},
60
- autoplay: { type: Boolean, default: !0 },
61
- loop: { type: Boolean, default: !1 },
62
- download: { type: [String, Function, Boolean], default: () => (s) => s.replace("/stream", "/download") },
63
- resetOnEnd: { type: Boolean, default: !1 },
64
- countdownTimeMode: { type: Boolean },
65
- hideVolumeSlider: { type: Boolean, default: !1 },
66
- closable: { type: Boolean, default: !0 },
67
- position: { default: "sticky" }
68
- },
69
- emits: ["initialized", "close"],
70
- setup(s, { emit: d }) {
71
- const e = s, v = k(() => {
72
- if (!e.src?.type) return e.src;
73
- const t = b(e.src.type);
74
- return {
75
- src: e.src.src,
76
- type: t
77
- };
78
- });
79
- function b(t) {
80
- return [
81
- "audio/wav"
82
- ].includes(t) ? "audio/mp3" : t;
83
- }
84
- function $() {
85
- const t = typeof e.src == "string" ? e.src : e.src?.src, n = typeof e.download == "function" ? e.download(t) : e.download, i = e.src?.type.split("/").pop(), m = e.id || "unknown", c = document.createElement("a");
86
- c.style.display = "none", c.href = n, c.download = `${m}.${i}`, document.body.appendChild(c), c.click(), document.body.removeChild(c);
87
- }
88
- function h(t) {
89
- if (!e.resetOnEnd) return;
90
- const n = t.target;
91
- n.currentTime = 0;
92
- }
93
- return (t, n) => {
94
- const i = f("wt-icon-btn");
95
- return l(), a("media-player", {
96
- class: B(["wt-player", `wt-player--position-${e.position}`]),
97
- src: v.value,
98
- loop: e.loop,
99
- autoplay: s.autoplay,
100
- onEnded: h
101
- }, [
102
- n[1] || (n[1] = _("media-provider", null, null, -1)),
103
- _("media-controls-group", U, [
104
- o(I),
105
- o(O),
106
- o(C, {
107
- countdown: e.countdownTimeMode
108
- }, null, 8, ["countdown"]),
109
- o(V),
110
- e.hideVolumeSlider ? p("", !0) : (l(), z(F, { key: 0 })),
111
- e.download ? (l(), a("media-button", {
112
- key: 1,
113
- class: "download-button",
114
- onClick: $
115
- }, [
116
- o(i, {
117
- icon: "plyr-download",
118
- size: "sm"
119
- })
120
- ])) : p("", !0),
121
- e.closable ? (l(), a("media-button", {
122
- key: 2,
123
- class: "close-button",
124
- onClick: n[0] || (n[0] = (m) => t.$emit("close"))
125
- }, [
126
- o(i, {
127
- icon: "close",
128
- size: "sm"
129
- })
130
- ])) : p("", !0)
131
- ])
132
- ], 42, G);
133
- };
134
- }
135
- }), K = /* @__PURE__ */ r(j, [["__scopeId", "data-v-efd4654a"]]);
136
- export {
137
- K as default
138
- };