@tamagui/core 1.0.1-beta.214 → 1.0.1-beta.215

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 (46) hide show
  1. package/dist/cjs/constants/isDevTools.js +9 -1
  2. package/dist/cjs/constants/isDevTools.js.map +2 -2
  3. package/dist/cjs/createComponent.js +71 -152
  4. package/dist/cjs/createComponent.js.map +3 -3
  5. package/dist/cjs/helpers/getSplitStyles.js +74 -47
  6. package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
  7. package/dist/cjs/helpers/getStylesAtomic.js +5 -1
  8. package/dist/cjs/helpers/getStylesAtomic.js.map +2 -2
  9. package/dist/cjs/helpers/normalizeValueWithProperty.js +9 -5
  10. package/dist/cjs/helpers/normalizeValueWithProperty.js.map +2 -2
  11. package/dist/cjs/helpers/pseudoDescriptors.js +10 -0
  12. package/dist/cjs/helpers/pseudoDescriptors.js.map +2 -2
  13. package/dist/cjs/helpers/useShallowSetState.js +1 -1
  14. package/dist/cjs/helpers/useShallowSetState.js.map +2 -2
  15. package/dist/cjs/types.js.map +1 -1
  16. package/dist/cjs/views/TamaguiProvider.js +2 -5
  17. package/dist/cjs/views/TamaguiProvider.js.map +3 -3
  18. package/dist/esm/constants/isDevTools.js +9 -1
  19. package/dist/esm/constants/isDevTools.js.map +2 -2
  20. package/dist/esm/createComponent.js +72 -152
  21. package/dist/esm/createComponent.js.map +3 -3
  22. package/dist/esm/helpers/getSplitStyles.js +75 -48
  23. package/dist/esm/helpers/getSplitStyles.js.map +2 -2
  24. package/dist/esm/helpers/getStylesAtomic.js +5 -1
  25. package/dist/esm/helpers/getStylesAtomic.js.map +2 -2
  26. package/dist/esm/helpers/normalizeValueWithProperty.js +9 -5
  27. package/dist/esm/helpers/normalizeValueWithProperty.js.map +2 -2
  28. package/dist/esm/helpers/pseudoDescriptors.js +10 -0
  29. package/dist/esm/helpers/pseudoDescriptors.js.map +2 -2
  30. package/dist/esm/helpers/useShallowSetState.js +1 -1
  31. package/dist/esm/helpers/useShallowSetState.js.map +2 -2
  32. package/dist/esm/views/TamaguiProvider.js +2 -5
  33. package/dist/esm/views/TamaguiProvider.js.map +3 -3
  34. package/package.json +12 -12
  35. package/src/constants/isDevTools.ts +10 -4
  36. package/src/createComponent.tsx +85 -200
  37. package/src/helpers/getSplitStyles.tsx +91 -57
  38. package/src/helpers/getStylesAtomic.ts +7 -2
  39. package/src/helpers/normalizeValueWithProperty.ts +11 -5
  40. package/src/helpers/pseudoDescriptors.ts +24 -3
  41. package/src/helpers/useShallowSetState.tsx +1 -1
  42. package/src/types.tsx +1 -1
  43. package/src/views/TamaguiProvider.tsx +5 -6
  44. package/types/helpers/getSplitStyles.d.ts +1 -1
  45. package/types/helpers/pseudoDescriptors.d.ts +8 -14
  46. package/types/types.d.ts +1 -1
@@ -3,6 +3,7 @@ import { useComposedRefs } from "@tamagui/compose-refs";
3
3
  import { isClient, isRSC, isWeb, useIsomorphicLayoutEffect } from "@tamagui/constants";
4
4
  import {
5
5
  composeEventHandlers,
6
+ stylePropsTransform,
6
7
  stylePropsView,
7
8
  validPseudoKeys,
8
9
  validStyles
@@ -32,6 +33,7 @@ import {
32
33
  } from "./helpers/getSplitStyles";
33
34
  import { getAllSelectors } from "./helpers/insertStyleRule";
34
35
  import { mergeProps } from "./helpers/mergeProps";
36
+ import { mergeTransform } from "./helpers/mergeTransform";
35
37
  import { proxyThemeVariables } from "./helpers/proxyThemeVariables";
36
38
  import { useShallowSetState } from "./helpers/useShallowSetState";
37
39
  import { getRect, measureLayout, useElementLayout } from "./hooks/useElementLayout";
@@ -98,11 +100,6 @@ function createComponent(configIn, ParentComponent) {
98
100
  const { Component, isText, isZStack } = staticConfig;
99
101
  const componentName = props.componentName || staticConfig.componentName;
100
102
  const componentClassName = props.asChild ? "" : props.componentName ? `is_${props.componentName}` : defaultComponentClassName;
101
- if (debugProp) {
102
- console.log(`render ${componentName}`);
103
- }
104
- const forceUpdate = useForceUpdate();
105
- const theme = useTheme(props.theme, componentName, props, forceUpdate);
106
103
  const hasEnterStyle = !!props.enterStyle;
107
104
  const needsMount = Boolean((isWeb ? isClient : true) && (hasEnterStyle || props.animation));
108
105
  const states = useServerState(
@@ -111,42 +108,47 @@ function createComponent(configIn, ParentComponent) {
111
108
  const state = propsIn.forceStyle ? { ...states[0], [propsIn.forceStyle]: true } : states[0];
112
109
  const setState = states[1];
113
110
  const setStateShallow = useShallowSetState(setState, debugProp, componentName);
114
- const shouldSetMounted = needsMount && !state.mounted;
111
+ const useAnimations = (_a = tamaguiConfig.animations) == null ? void 0 : _a.useAnimations;
112
+ const hasEverAnimated = useRef(false);
113
+ const isAnimated = (() => {
114
+ const next = !!(useAnimations && props.animation);
115
+ if (next && !hasEverAnimated.current) {
116
+ hasEverAnimated.current = true;
117
+ }
118
+ return next || hasEverAnimated.current;
119
+ })();
120
+ const isReactNative = Boolean(
121
+ staticConfig.isReactNative || isAnimated && tamaguiConfig.animations.isReactNative
122
+ );
123
+ if (process.env.NODE_ENV === "development") {
124
+ if (props["debug"]) {
125
+ const name = `${componentName || (Component == null ? void 0 : Component.displayName) || (Component == null ? void 0 : Component.name) || "[Unnamed Component]"}`;
126
+ const type = isReactNative ? "(rnw)" : "";
127
+ const dataIs = propsIn["data-is"] || "";
128
+ const banner = `${name}${dataIs ? ` ${dataIs}` : ""} ${type}`;
129
+ console.group(`%c ${banner}`, "background: yellow;");
130
+ console.log(`state`, state);
131
+ }
132
+ }
133
+ const forceUpdate = useForceUpdate();
134
+ const theme = useTheme(props.theme, componentName, props, forceUpdate);
135
+ const shouldSetMounted = needsMount && state.unmounted;
115
136
  const setMounted = shouldSetMounted ? () => {
116
137
  setTimeout(
117
138
  () => {
118
139
  setStateShallow({
119
- mounted: true
140
+ unmounted: false
120
141
  });
121
142
  },
122
143
  isWeb ? 10 : 0
123
144
  );
124
145
  } : void 0;
125
- const shouldAvoidClasses = !!(props.animation && avoidClassesWhileAnimating) || !staticConfig.acceptsClassName;
146
+ const shouldAvoidClasses = !isWeb || !!(props.animation && avoidClassesWhileAnimating) || !staticConfig.acceptsClassName;
126
147
  const shouldForcePseudo = !!propsIn.forceStyle;
127
148
  const hasTextAncestor = !!(isWeb && isText ? useContext(TextAncestorContext) : false);
128
- const splitStyleState = !shouldAvoidClasses && !shouldForcePseudo ? {
129
- ...state,
130
- hasTextAncestor,
131
- dynamicStylesInline: true
132
- } : {
133
- ...state,
134
- noClassNames: true,
135
- dynamicStylesInline: true,
136
- hasTextAncestor,
137
- resolveVariablesAs: "value"
138
- };
149
+ const noClassNames = shouldAvoidClasses || shouldForcePseudo;
139
150
  const languageContext = isRSC ? null : useContext(FontLanguageContext);
140
- const isDisabled = props.disabled ?? ((_a = props.accessibilityState) == null ? void 0 : _a.disabled);
141
- const useAnimations = (_b = tamaguiConfig.animations) == null ? void 0 : _b.useAnimations;
142
- const hasEverAnimated = useRef(false);
143
- const isAnimated = (() => {
144
- const next = !!(useAnimations && props.animation);
145
- if (next && !hasEverAnimated.current) {
146
- hasEverAnimated.current = true;
147
- }
148
- return next || hasEverAnimated.current;
149
- })();
151
+ const isDisabled = props.disabled ?? ((_b = props.accessibilityState) == null ? void 0 : _b.disabled);
150
152
  const isTaggable = !Component || typeof Component === "string";
151
153
  const element = isWeb ? isTaggable ? props.tag || defaultTag || Component : Component : Component;
152
154
  const BaseTextComponent = BaseText || element || "span";
@@ -154,6 +156,13 @@ function createComponent(configIn, ParentComponent) {
154
156
  let elementType = isText ? (isAnimated ? AnimatedText : null) || BaseTextComponent : (isAnimated ? AnimatedView : null) || BaseViewComponent;
155
157
  elementType = Component || elementType;
156
158
  const isStringElement = typeof elementType === "string";
159
+ const splitStyleState = {
160
+ ...state,
161
+ noClassNames,
162
+ dynamicStylesInline: noClassNames,
163
+ hasTextAncestor,
164
+ resolveVariablesAs: "value"
165
+ };
157
166
  const splitStyles = useSplitStyles(
158
167
  props,
159
168
  staticConfig,
@@ -165,24 +174,17 @@ function createComponent(configIn, ParentComponent) {
165
174
  debugProp
166
175
  );
167
176
  const hostRef = useServerRef(null);
168
- const isReactNative = Boolean(
169
- staticConfig.isReactNative || isAnimated && tamaguiConfig.animations.isReactNative
170
- );
171
177
  const isAnimatedReactNativeWeb = isAnimated && avoidClassesWhileAnimating;
172
178
  if (process.env.NODE_ENV === "development") {
173
179
  if (!process.env.TAMAGUI_TARGET) {
174
180
  console.error(`No process.env.TAMAGUI_TARGET set, please set it to "native" or "web".`);
175
181
  }
176
182
  if (debugProp) {
177
- const name = `${componentName || (Component == null ? void 0 : Component.displayName) || (Component == null ? void 0 : Component.name) || "[Unnamed Component]"}`;
178
- const type = isReactNative ? "rnw" : "tamagui";
179
- const banner = `${name} ${propsIn["data-is"] || ""} ${type}`;
180
- console.group(`%c \u{1F41B} ${banner}`, "background: yellow;");
181
- console.groupCollapsed("initial props/state");
182
- console.log("propsIn", propsIn, "turned into", props, "order", Object.keys(props));
183
+ console.groupCollapsed("props");
184
+ console.log("props in", propsIn, "mapped to", props, "in order", Object.keys(props));
183
185
  console.log("splitStyles", splitStyles);
184
186
  console.log("className", Object.values(splitStyles.classNames));
185
- if (typeof window !== "undefined") {
187
+ if (isClient) {
186
188
  console.log("ref", hostRef, "(click to view)");
187
189
  }
188
190
  console.groupEnd();
@@ -199,7 +201,6 @@ function createComponent(configIn, ParentComponent) {
199
201
  classNames,
200
202
  mediaKeys
201
203
  } = splitStyles;
202
- const animationFeatureStylesIn = props.animation ? { ...defaultNativeStyle, ...splitStylesStyle } : null;
203
204
  const propsWithAnimation = props;
204
205
  let animationStyles;
205
206
  if (!isRSC && isAnimated && useAnimations) {
@@ -211,7 +212,7 @@ function createComponent(configIn, ParentComponent) {
211
212
  staticConfig,
212
213
  getStyle({ isExiting, isEntering, exitVariant, enterVariant } = {}) {
213
214
  var _a2, _b2, _c2, _d2;
214
- const style = animationFeatureStylesIn;
215
+ const animationStyle = { ...defaultNativeStyle, ...splitStylesStyle };
215
216
  const enterStyle = isEntering ? enterVariant && ((_a2 = staticConfig.variants) == null ? void 0 : _a2[enterVariant]["true"]) ? getSubStyle(
216
217
  "",
217
218
  (_b2 = staticConfig.variants) == null ? void 0 : _b2[enterVariant]["true"],
@@ -220,7 +221,7 @@ function createComponent(configIn, ParentComponent) {
220
221
  props,
221
222
  state,
222
223
  tamaguiConfig
223
- ) || pseudos.enterStyle : pseudos.enterStyle : null;
224
+ ) : null : null;
224
225
  const exitStyle = isExiting ? exitVariant && ((_c2 = staticConfig.variants) == null ? void 0 : _c2[exitVariant]["true"]) ? getSubStyle(
225
226
  "",
226
227
  (_d2 = staticConfig.variants) == null ? void 0 : _d2[exitVariant]["true"],
@@ -229,24 +230,14 @@ function createComponent(configIn, ParentComponent) {
229
230
  props,
230
231
  state,
231
232
  tamaguiConfig
232
- ) || pseudos.exitStyle : pseudos.exitStyle : null;
233
- ensureBaseHasDefaults(
234
- style,
235
- pseudos.hoverStyle,
236
- pseudos.focusStyle,
237
- pseudos.pressStyle
238
- );
239
- enterStyle && isEntering && merge(style, enterStyle);
240
- state.hover && pseudos.hoverStyle && merge(style, pseudos.hoverStyle);
241
- state.focus && pseudos.focusStyle && merge(style, pseudos.focusStyle);
242
- state.press && pseudos.pressStyle && merge(style, pseudos.pressStyle);
243
- exitStyle && isExiting && merge(style, exitStyle);
244
- if (process.env.NODE_ENV === "development") {
245
- if (debugProp === "verbose") {
246
- console.log("animation style", style);
247
- }
233
+ ) : pseudos.exitStyle : null;
234
+ if (isEntering && enterStyle) {
235
+ merge(animationStyle, enterStyle);
236
+ }
237
+ if (isExiting && exitStyle) {
238
+ merge(animationStyle, exitStyle);
248
239
  }
249
- return style;
240
+ return animationStyle;
250
241
  }
251
242
  });
252
243
  if (animations) {
@@ -418,13 +409,6 @@ function createComponent(configIn, ParentComponent) {
418
409
  };
419
410
  } else {
420
411
  styles = [isWeb ? null : defaultNativeStyle, animationStyles ?? splitStylesStyle, medias];
421
- if (!animationStyles && initialSplitStyles) {
422
- const initPseudos = initialSplitStyles.pseudos;
423
- !state.mounted && addPseudoToStyles(styles, initPseudos, pseudos, "enterStyle");
424
- state.hover && addPseudoToStyles(styles, initPseudos, pseudos, "hoverStyle", shouldForcePseudo);
425
- state.focus && addPseudoToStyles(styles, initPseudos, pseudos, "focusStyle", shouldForcePseudo);
426
- state.press && addPseudoToStyles(styles, initPseudos, pseudos, "pressStyle", shouldForcePseudo);
427
- }
428
412
  if (shouldForcePseudo) {
429
413
  const next = {};
430
414
  for (const style of styles) {
@@ -498,9 +482,11 @@ function createComponent(configIn, ParentComponent) {
498
482
  viewProps.style = styles;
499
483
  }
500
484
  const initialPseudos = initialSplitStyles == null ? void 0 : initialSplitStyles.pseudos;
501
- const attachPress = !!((pseudos == null ? void 0 : pseudos.pressStyle) || (initialPseudos == null ? void 0 : initialPseudos.pressStyle) || onPress || onPressOut || onPressIn || onClick);
485
+ const runtimePressStyle = noClassNames && ((pseudos == null ? void 0 : pseudos.pressStyle) || (initialPseudos == null ? void 0 : initialPseudos.pressStyle));
486
+ const attachPress = !!(runtimePressStyle || onPress || onPressOut || onPressIn || onClick);
502
487
  const isHoverable = isWeb;
503
- const attachHover = isHoverable && !!(pseudos && pseudos.hoverStyle || onHoverIn || onHoverOut || onMouseEnter || onMouseLeave);
488
+ const runtimeHoverStyle = noClassNames && ((pseudos == null ? void 0 : pseudos.hoverStyle) || initialPseudos.hoverStyle);
489
+ const attachHover = isHoverable && !!(runtimeHoverStyle || onHoverIn || onHoverOut || onMouseEnter || onMouseLeave);
504
490
  const handlesPressEvents = !isWeb && !asChild;
505
491
  const shouldAttach = asChild ? false : Boolean(
506
492
  attachPress || attachHover || "pressStyle" in props || "onPress" in props || "onPressIn" in props || "onPressOut" in props || isWeb && ("hoverStyle" in props || "onHoverIn" in props || "onHoverOut" in props || "onMouseEnter" in props || "onMouseLeave" in props)
@@ -511,7 +497,7 @@ function createComponent(configIn, ParentComponent) {
511
497
  onPressOut == null ? void 0 : onPressOut(e);
512
498
  onMouseUp == null ? void 0 : onMouseUp(e);
513
499
  } : void 0,
514
- ...isHoverable && {
500
+ ...attachHover && {
515
501
  onMouseEnter: attachHover ? (e) => {
516
502
  const next = {};
517
503
  if (attachHover) {
@@ -606,7 +592,7 @@ function createComponent(configIn, ParentComponent) {
606
592
  };
607
593
  }
608
594
  if (process.env.TAMAGUI_TARGET === "native") {
609
- const attachFocus = !!(pseudos && pseudos.focusStyle || initialPseudos && initialPseudos.focusStyle);
595
+ const attachFocus = !!(pseudos.focusStyle || initialPseudos && initialPseudos.focusStyle);
610
596
  if (attachFocus) {
611
597
  viewProps.onFocus = mergeEvent(viewProps.onFocus, () => {
612
598
  setStateShallow({ focus: true });
@@ -615,11 +601,8 @@ function createComponent(configIn, ParentComponent) {
615
601
  setStateShallow({ focus: false });
616
602
  });
617
603
  }
618
- const pressability = usePressability(events);
604
+ const pressability = usePressability(events ? { ...events, hitSlop } : {});
619
605
  if (attachPress && events) {
620
- if (hitSlop) {
621
- viewProps.hitSlop = hitSlop;
622
- }
623
606
  for (const key in pressability) {
624
607
  const og = props[key];
625
608
  const val = pressability[key];
@@ -674,12 +657,12 @@ function createComponent(configIn, ParentComponent) {
674
657
  press: false,
675
658
  pressIn: false,
676
659
  focus: false,
677
- mounted: false,
660
+ unmounted: true,
678
661
  mediaState: getMediaStateObject(getInitialMediaState())
679
662
  };
680
663
  defaultComponentStateMounted = {
681
664
  ...defaultComponentState,
682
- mounted: true
665
+ unmounted: false
683
666
  };
684
667
  }
685
668
  if (tamaguiConfig.animations) {
@@ -719,22 +702,21 @@ function createComponent(configIn, ParentComponent) {
719
702
  staticConfig,
720
703
  initialTheme,
721
704
  {
722
- mounted: true,
705
+ unmounted: false,
723
706
  hover: false,
724
707
  press: false,
725
708
  pressIn: false,
726
709
  focus: false,
727
710
  resolveVariablesAs: "both",
728
- noClassNames,
729
- keepVariantsAsProps: true
711
+ noClassNames
730
712
  },
731
713
  void 0,
732
714
  void 0,
733
715
  debug
734
716
  );
735
- const [defaults2, defaultsClassnames] = mergeProps(
717
+ const [defaults, defaultsClassnames] = mergeProps(
736
718
  component.defaultProps,
737
- initialSplitStyles.viewProps,
719
+ { ...initialSplitStyles.pseudos, ...initialSplitStyles.viewProps },
738
720
  true
739
721
  );
740
722
  initialSplitStyles.classNames = {
@@ -750,14 +732,14 @@ function createComponent(configIn, ParentComponent) {
750
732
  if (validPseudoKeys[key])
751
733
  continue;
752
734
  if (typeof val === "string" && val[0] === "$" || !validStyles2[key]) {
753
- defaults2[key] = val;
735
+ defaults[key] = val;
754
736
  } else {
755
737
  defaultNativeStyle[key] = val;
756
738
  }
757
739
  }
758
740
  }
759
- if (Object.keys(defaults2).length) {
760
- tamaguiDefaultProps = defaults2;
741
+ if (Object.keys(defaults).length) {
742
+ tamaguiDefaultProps = defaults;
761
743
  }
762
744
  if (process.env.NODE_ENV === "development" && debug) {
763
745
  if (process.env.IS_STATIC !== "is_static") {
@@ -766,7 +748,7 @@ function createComponent(configIn, ParentComponent) {
766
748
  initialSplitStyles,
767
749
  tamaguiDefaultProps,
768
750
  defaultNativeStyle,
769
- defaults: defaults2,
751
+ defaults,
770
752
  defaultPropsIn,
771
753
  defaultPropsKeyOrder: Object.keys(staticConfig.defaultProps),
772
754
  defaultPropsInKeyOrder: Object.keys(defaultPropsIn).map((k) => [k, defaultPropsIn[k]]),
@@ -939,15 +921,6 @@ function isUnspaced(child) {
939
921
  var _a, _b;
940
922
  return ((_a = child == null ? void 0 : child["type"]) == null ? void 0 : _a["isVisuallyHidden"]) || ((_b = child == null ? void 0 : child["type"]) == null ? void 0 : _b["isUnspaced"]);
941
923
  }
942
- function addPseudoToStyles(styles, initialPseudos, pseudos, name, force = false) {
943
- const pseudoStyle = pseudos[name];
944
- const shouldNestObject = isWeb && name !== "enterStyle" && name !== "exitStyle";
945
- const defaultPseudoStyle = initialPseudos[name];
946
- const style = defaultPseudoStyle ? { ...defaultPseudoStyle, ...pseudoStyle } : pseudoStyle;
947
- if (style) {
948
- styles.push(shouldNestObject && !force ? { [name]: style } : style);
949
- }
950
- }
951
924
  const DefaultProps = /* @__PURE__ */ new Map();
952
925
  function mergeConfigDefaultProps(name, props, configDefaults, parentNames, conf) {
953
926
  const len = parentNames.length;
@@ -976,66 +949,13 @@ function mergeConfigDefaultProps(name, props, configDefaults, parentNames, conf)
976
949
  }
977
950
  return props;
978
951
  }
979
- const defaults = {
980
- left: 0,
981
- right: 0,
982
- top: 0,
983
- bottom: 0,
984
- opacity: 1,
985
- translateX: 0,
986
- translateY: 0,
987
- skew: 0,
988
- skewX: 0,
989
- skewY: 0,
990
- scale: 1,
991
- rotate: "0deg",
992
- rotateY: "0deg",
993
- rotateX: "0deg"
994
- };
995
- function ensureBaseHasDefaults(base, ...pseudos) {
996
- for (const pseudo of pseudos) {
997
- if (!pseudo)
998
- continue;
999
- for (const key in pseudo) {
1000
- const val = pseudo[key];
1001
- if (key === "transform") {
1002
- if (typeof val === "string") {
1003
- continue;
1004
- }
1005
- for (const t of val) {
1006
- const tkey = Object.keys(t)[0];
1007
- const defaultVal = defaults[tkey];
1008
- const tDefaultVal = { [tkey]: defaultVal };
1009
- if (!base.transform) {
1010
- base.transform = [tDefaultVal];
1011
- } else {
1012
- if (!base.transform.find((x) => x[tkey])) {
1013
- base.transform.push(tDefaultVal);
1014
- }
1015
- }
1016
- }
1017
- } else {
1018
- if (!(key in base)) {
1019
- base[key] = defaults[key];
1020
- }
1021
- }
1022
- }
1023
- }
1024
- }
1025
952
  function merge(base, next) {
1026
- if (!next.transform || !base.transform) {
1027
- Object.assign(base, next);
1028
- return;
1029
- }
1030
- const { transform, ...rest } = next;
1031
- Object.assign(base, rest);
1032
- for (const t of transform) {
1033
- const key = Object.keys(t)[0];
1034
- const existing = base.transform.find((x) => key in x);
1035
- if (existing) {
1036
- existing[key] = t[key];
953
+ for (const key in next) {
954
+ const val = next[key];
955
+ if (key in stylePropsTransform) {
956
+ mergeTransform(base, key, val, true);
1037
957
  } else {
1038
- base.transform.push(t);
958
+ base[key] = val;
1039
959
  }
1040
960
  }
1041
961
  }