})"
`;
+exports[`SFC compile <script setup> > with TypeScript > defineSlots() > basic usage 1`] = `
+"import { useSlots as _useSlots, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const slots = _useSlots()
+
+return { slots }
+}
+
+})"
+`;
+
+exports[`SFC compile <script setup> > with TypeScript > defineSlots() > w/o generic params 1`] = `
+"import { useSlots as _useSlots } from 'vue'
+
+export default {
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const slots = _useSlots()
+
+return { slots }
+}
+
+}"
+`;
+
+exports[`SFC compile <script setup> > with TypeScript > defineSlots() > w/o return value 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
exports[`SFC compile <script setup> > with TypeScript > hoist type declarations 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
export interface Foo {}
assertCode(content)
})
+ describe('defineSlots()', () => {
+ test('basic usage', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const slots = defineSlots<{
+ default: { msg: string }
+ }>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const slots = _useSlots()`)
+ expect(content).not.toMatch('defineSlots')
+ })
+
+ test('w/o return value', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ defineSlots<{
+ default: { msg: string }
+ }>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).not.toMatch('defineSlots')
+ expect(content).not.toMatch(`_useSlots`)
+ })
+
+ test('w/o generic params', () => {
+ const { content } = compile(`
+ <script setup>
+ const slots = defineSlots()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const slots = _useSlots()`)
+ expect(content).not.toMatch('defineSlots')
+ })
+ })
+
test('runtime Enum', () => {
const { content, bindings } = compile(
`<script setup lang="ts">
const DEFINE_EXPOSE = 'defineExpose'
const WITH_DEFAULTS = 'withDefaults'
const DEFINE_OPTIONS = 'defineOptions'
+const DEFINE_SLOTS = 'defineSlots'
const isBuiltInDir = makeMap(
`once,memo,if,for,else,else-if,slot,text,html,on,bind,model,show,cloak,is`
let hasDefaultExportName = false
let hasDefaultExportRender = false
let hasDefineOptionsCall = false
+ let hasDefineSlotsCall = false
let propsRuntimeDecl: Node | undefined
let propsRuntimeDefaults: Node | undefined
let propsDestructureDecl: Node | undefined
return true
}
+ function processDefineSlots(node: Node, declId?: LVal): boolean {
+ if (!isCallOf(node, DEFINE_SLOTS)) {
+ return false
+ }
+ if (hasDefineSlotsCall) {
+ error(`duplicate ${DEFINE_SLOTS}() call`, node)
+ }
+ hasDefineSlotsCall = true
+
+ if (node.arguments.length > 0) {
+ error(`${DEFINE_SLOTS}() cannot accept arguments`, node)
+ }
+
+ if (declId) {
+ s.overwrite(
+ startOffset + node.start!,
+ startOffset + node.end!,
+ `${helper('useSlots')}()`
+ )
+ }
+
+ return true
+ }
+
function getAstBody(): Statement[] {
return scriptAst
? [...scriptSetupAst.body, ...scriptAst.body]
let propsOption = undefined
let emitsOption = undefined
let exposeOption = undefined
+ let slotsOption = undefined
if (optionsRuntimeDecl.type === 'ObjectExpression') {
for (const prop of optionsRuntimeDecl.properties) {
if (
if (prop.key.name === 'props') propsOption = prop
if (prop.key.name === 'emits') emitsOption = prop
if (prop.key.name === 'expose') exposeOption = prop
+ if (prop.key.name === 'slots') slotsOption = prop
}
}
}
exposeOption
)
}
+ if (slotsOption) {
+ error(
+ `${DEFINE_OPTIONS}() cannot be used to declare slots. Use ${DEFINE_SLOTS}() instead.`,
+ slotsOption
+ )
+ }
return true
}
processDefineProps(expr) ||
processDefineEmits(expr) ||
processDefineOptions(expr) ||
- processWithDefaults(expr)
+ processWithDefaults(expr) ||
+ processDefineSlots(expr)
) {
s.remove(node.start! + startOffset, node.end! + startOffset)
} else if (processDefineExpose(expr)) {
const isDefineProps =
processDefineProps(init, decl.id) ||
processWithDefaults(init, decl.id)
- const isDefineEmits = processDefineEmits(init, decl.id)
+ const isDefineEmits =
+ !isDefineProps && processDefineEmits(init, decl.id)
+ !isDefineEmits && processDefineSlots(init, decl.id)
+
if (isDefineProps || isDefineEmits) {
if (left === 1) {
s.remove(node.start! + startOffset, node.end! + startOffset)
ComponentPublicInstance,
ComponentOptions,
SetupContext,
- h
+ h,
+ SlotsType,
+ Slots,
+ VNode
} from 'vue'
import { describe, expectType, IsUnion } from './utils'
})
}
+describe('slots', () => {
+ const comp1 = defineComponent({
+ slots: Object as SlotsType<{
+ default: { foo: string; bar: number }
+ optional?: { data: string }
+ undefinedScope: undefined | { data: string }
+ optionalUndefinedScope?: undefined | { data: string }
+ }>,
+ setup(props, { slots }) {
+ expectType<(scope: { foo: string; bar: number }) => VNode[]>(
+ slots.default
+ )
+ expectType<((scope: { data: string }) => VNode[]) | undefined>(
+ slots.optional
+ )
+
+ slots.default({ foo: 'foo', bar: 1 })
+
+ // @ts-expect-error it's optional
+ slots.optional({ data: 'foo' })
+ slots.optional?.({ data: 'foo' })
+
+ expectType<{
+ (): VNode[]
+ (scope: undefined | { data: string }): VNode[]
+ }>(slots.undefinedScope)
+
+ expectType<
+ | { (): VNode[]; (scope: undefined | { data: string }): VNode[] }
+ | undefined
+ >(slots.optionalUndefinedScope)
+
+ slots.default({ foo: 'foo', bar: 1 })
+ // @ts-expect-error it's optional
+ slots.optional({ data: 'foo' })
+ slots.optional?.({ data: 'foo' })
+ slots.undefinedScope()
+ slots.undefinedScope(undefined)
+ // @ts-expect-error
+ slots.undefinedScope('foo')
+
+ slots.optionalUndefinedScope?.()
+ slots.optionalUndefinedScope?.(undefined)
+ slots.optionalUndefinedScope?.({ data: 'foo' })
+ // @ts-expect-error
+ slots.optionalUndefinedScope()
+ // @ts-expect-error
+ slots.optionalUndefinedScope?.('foo')
+
+ expectType<typeof slots | undefined>(new comp1().$slots)
+ }
+ })
+
+ const comp2 = defineComponent({
+ setup(props, { slots }) {
+ // unknown slots
+ expectType<Slots>(slots)
+ expectType<((...args: any[]) => VNode[]) | undefined>(slots.default)
+ }
+ })
+ expectType<Slots | undefined>(new comp2().$slots)
+})
+
import {
DefineComponent,
ComponentOptionsMixin,
ComponentOptionsMixin,
EmitsOptions,
string,
+ {},
VNodeProps & AllowedComponentProps & ComponentCustomProps,
Readonly<ExtractPropTypes<{}>>,
{}
-import { h, Text, FunctionalComponent, Component } from 'vue'
+import { h, Text, FunctionalComponent, Component, VNode } from 'vue'
import { expectType } from './utils'
// simple function signature
}
expectType<Component>(Qux)
+
+const Quux: FunctionalComponent<
+ {},
+ {},
+ {
+ default: { foo: number }
+ optional?: { foo: number }
+ }
+> = (props, { emit, slots }) => {
+ expectType<{
+ default: (scope: { foo: number }) => VNode[]
+ optional?: (scope: { foo: number }) => VNode[]
+ }>(slots)
+
+ slots.default({ foo: 123 })
+ // @ts-expect-error
+ slots.default({ foo: 'fesf' })
+
+ slots.optional?.({ foo: 123 })
+ // @ts-expect-error
+ slots.optional?.({ foo: 'fesf' })
+ // @ts-expect-error
+ slots.optional({ foo: 123 })
+}
+expectType<Component>(Quux)
+;<Quux />
useAttrs,
useSlots,
withDefaults,
- Slots
+ Slots,
+ defineSlots,
+ VNode
} from 'vue'
import { describe, expectType } from './utils'
emit2('baz')
})
+describe('defineSlots', () => {
+ // short syntax
+ const slots = defineSlots<{
+ default: { foo: string; bar: number }
+ optional?: string
+ }>()
+ expectType<(scope: { foo: string; bar: number }) => VNode[]>(slots.default)
+ expectType<undefined | ((scope: string) => VNode[])>(slots.optional)
+
+ // literal fn syntax (allow for specifying return type)
+ const fnSlots = defineSlots<{
+ default(props: { foo: string; bar: number }): any
+ optional?(props: string): any
+ }>()
+ expectType<(scope: { foo: string; bar: number }) => VNode[]>(fnSlots.default)
+ expectType<undefined | ((scope: string) => VNode[])>(fnSlots.optional)
+
+ const slotsUntype = defineSlots()
+ expectType<Slots>(slotsUntype)
+})
+
describe('useAttrs', () => {
const attrs = useAttrs()
expectType<Record<string, unknown>>(attrs)
CreateComponentPublicInstance,
ComponentPublicInstanceConstructor
} from './componentPublicInstance'
+import { SlotsType } from './componentSlots'
export type PublicProps = VNodeProps &
AllowedComponentProps &
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
EE extends string = string,
+ S extends SlotsType = {},
PP = PublicProps,
Props = Readonly<
PropsOrPropOptions extends ComponentPropsOptions
Mixin,
Extends,
E,
+ S,
PP & Props,
Defaults,
true
Extends,
E,
EE,
+ S,
Defaults
> &
PP
export function defineComponent<
Props extends Record<string, any>,
E extends EmitsOptions = {},
- EE extends string = string
+ EE extends string = string,
+ S extends SlotsType = {}
>(
setup: (
props: Props,
- ctx: SetupContext<E>
+ ctx: SetupContext<E, S>
) => RenderFunction | Promise<RenderFunction>,
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs'> & {
props?: (keyof Props)[]
emits?: E | EE[]
+ slots?: S
}
): (props: Props & EmitsToProps<E>) => any
export function defineComponent<
Props extends Record<string, any>,
E extends EmitsOptions = {},
- EE extends string = string
+ EE extends string = string,
+ S extends SlotsType = {}
>(
setup: (
props: Props,
- ctx: SetupContext<E>
+ ctx: SetupContext<E, S>
) => RenderFunction | Promise<RenderFunction>,
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs'> & {
props?: ComponentObjectPropsOptions<Props>
emits?: E | EE[]
+ slots?: S
}
): (props: Props & EmitsToProps<E>) => any
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string
>(
Extends,
E,
EE,
+ S,
I,
II
>
-): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>
+): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE, S>
// overload 3: object format with array props declaration
// props inferred as { [key in PropNames]?: any }
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string
>(
Extends,
E,
EE,
+ S,
I,
II
>
Mixin,
Extends,
E,
- EE
+ EE,
+ S
>
// overload 4: object format with object props declaration
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string
>(
Extends,
E,
EE,
+ S,
I,
II
>
-): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>
+): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE, S>
// implementation, close to no-op
export function defineComponent(
ExtractPropTypes
} from './componentProps'
import { warn } from './warning'
+import { SlotsType, TypedSlots } from './componentSlots'
// dev only
const warnRuntimeUsage = (method: string) =>
C extends ComputedOptions = {},
M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
- Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
- E extends EmitsOptions = EmitsOptions,
- EE extends string = string
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
>(
options?: ComponentOptionsWithoutProps<
{},
C,
M,
Mixin,
- Extends,
- E,
- EE
- > & { emits?: undefined; expose?: undefined }
+ Extends
+ > & { emits?: undefined; expose?: undefined; slots?: undefined }
): void {
if (__DEV__) {
warnRuntimeUsage(`defineOptions`)
}
}
+export function defineSlots<
+ S extends Record<string, any> = Record<string, any>
+>(): // @ts-expect-error
+TypedSlots<SlotsType<S>> {
+ if (__DEV__) {
+ warnRuntimeUsage(`defineSlots`)
+ }
+}
+
type NotUndefined<T> = T extends undefined ? never : T
type InferDefaults<T> = {
initProps,
normalizePropsOptions
} from './componentProps'
-import { Slots, initSlots, InternalSlots } from './componentSlots'
+import {
+ initSlots,
+ InternalSlots,
+ Slots,
+ SlotsType,
+ TypedSlots
+} from './componentSlots'
import { warn } from './warning'
import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
isPromise,
ShapeFlags,
extend,
- getGlobalThis
+ getGlobalThis,
+ IfAny
} from '@vue/shared'
import { SuspenseBoundary } from './components/Suspense'
import { CompilerOptions } from '@vue/compiler-core'
__name?: string
}
-export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
- extends ComponentInternalOptions {
+export interface FunctionalComponent<
+ P = {},
+ E extends EmitsOptions = {},
+ S extends Record<string, any> = any
+> extends ComponentInternalOptions {
// use of any here is intentional so it can be a valid JSX Element constructor
- (props: P, ctx: Omit<SetupContext<E>, 'expose'>): any
+ (
+ props: P,
+ ctx: Omit<SetupContext<E, IfAny<S, {}, SlotsType<S>>>, 'expose'>
+ ): any
props?: ComponentPropsOptions<P>
emits?: E | (keyof E)[]
+ slots?: IfAny<S, Slots, SlotsType<S>>
inheritAttrs?: boolean
displayName?: string
compatConfig?: CompatConfig
M extends MethodOptions = MethodOptions
> =
| ComponentOptions<Props, RawBindings, D, C, M>
- | FunctionalComponent<Props, any>
+ | FunctionalComponent<Props, any, any>
/**
* A type used in public APIs where a component type is expected.
type LifecycleHook<TFn = Function> = TFn[] | null
// use `E extends any` to force evaluating type to fix #2362
-export type SetupContext<E = EmitsOptions> = E extends any
+export type SetupContext<
+ E = EmitsOptions,
+ S extends SlotsType = {}
+> = E extends any
? {
attrs: Data
- slots: Slots
+ slots: TypedSlots<S>
emit: EmitFn<E>
expose: (exposed?: Record<string, any>) => void
}
} from './compat/compatConfig'
import { OptionMergeFunction } from './apiCreateApp'
import { LifecycleHooks } from './enums'
+import { SlotsType } from './componentSlots'
/**
* Interface for declaring custom options.
Extends extends ComponentOptionsMixin,
E extends EmitsOptions,
EE extends string = string,
+ S extends SlotsType = {},
Defaults = {},
I extends ComponentInjectOptions = {},
II extends string = string
>
>
>,
- ctx: SetupContext<E>
+ ctx: SetupContext<E, S>
) => Promise<RawBindings> | RawBindings | RenderFunction | void
name?: string
template?: string | object // can be a direct DOM node
directives?: Record<string, Directive>
inheritAttrs?: boolean
emits?: (E | EE[]) & ThisType<void>
+ slots?: S
// TODO infer public instance type based on exposed keys
expose?: string[]
serverPrefetch?(): void | Promise<any>
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions,
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string,
PE = Props & EmitsToProps<E>
Extends,
E,
EE,
+ S,
{},
I,
II
Mixin,
Extends,
E,
+ S,
PE,
{},
false,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions,
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string,
Props = Prettify<Readonly<{ [key in PropNames]?: any } & EmitsToProps<E>>>
Extends,
E,
EE,
+ S,
{},
I,
II
Mixin,
Extends,
E,
+ S,
Props,
{},
false,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions,
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string,
Props = Prettify<Readonly<ExtractPropTypes<PropsOptions> & EmitsToProps<E>>>,
Extends,
E,
EE,
+ S,
Defaults,
I,
II
Mixin,
Extends,
E,
+ S,
Props,
Defaults,
false,
M extends MethodOptions = any,
Mixin extends ComponentOptionsMixin = any,
Extends extends ComponentOptionsMixin = any,
- E extends EmitsOptions = any
-> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E> &
+ E extends EmitsOptions = any,
+ S extends SlotsType = any
+> = ComponentOptionsBase<
+ Props,
+ RawBindings,
+ D,
+ C,
+ M,
+ Mixin,
+ Extends,
+ E,
+ string,
+ S
+> &
ThisType<
CreateComponentPublicInstance<
{},
any,
any,
any,
+ any,
any
>
ComponentInjectOptions
} from './componentOptions'
import { EmitsOptions, EmitFn } from './componentEmits'
-import { Slots } from './componentSlots'
+import { SlotsType, TypedSlots } from './componentSlots'
import { markAttrsAccessed } from './componentRenderUtils'
import { currentRenderingInstance } from './componentRenderContext'
import { warn } from './warning'
infer Extends,
any,
any,
+ any,
infer Defaults
>
? OptionTypesType<P & {}, B & {}, D & {}, C & {}, M & {}, Defaults & {}> &
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
+ S extends SlotsType = {},
PublicProps = P,
Defaults = {},
MakeDefaultsOptional extends boolean = false,
PublicC,
PublicM,
E,
+ S,
PublicProps,
PublicDefaults,
MakeDefaultsOptional,
- ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E, string, Defaults>,
+ ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E, string, S, Defaults>,
I
>
C extends ComputedOptions = {},
M extends MethodOptions = {},
E extends EmitsOptions = {},
+ S extends SlotsType = {},
PublicProps = P,
Defaults = {},
MakeDefaultsOptional extends boolean = false,
>
$attrs: Data
$refs: Data
- $slots: Slots
+ $slots: TypedSlots<S>
$root: ComponentPublicInstance | null
$parent: ComponentPublicInstance | null
$emit: EmitFn<E>
ShapeFlags,
extend,
def,
- SlotFlags
+ SlotFlags,
+ Prettify,
+ IfAny
} from '@vue/shared'
import { warn } from './warning'
import { isKeepAlive } from './components/KeepAlive'
import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
import { toRaw } from '@vue/reactivity'
-export type Slot = (...args: any[]) => VNode[]
+export type Slot<T extends any = any> = (
+ ...args: IfAny<T, any[], [T] | (T extends undefined ? [] : never)>
+) => VNode[]
export type InternalSlots = {
[name: string]: Slot | undefined
export type Slots = Readonly<InternalSlots>
+declare const SlotSymbol: unique symbol
+export type SlotsType<T extends Record<string, any> = Record<string, any>> = {
+ [SlotSymbol]?: T
+}
+
+export type TypedSlots<
+ S extends SlotsType,
+ T = NonNullable<S[typeof SlotSymbol]>
+> = [keyof S] extends [never]
+ ? Slots
+ : Readonly<
+ Prettify<{
+ [K in keyof T]: NonNullable<T[K]> extends (...args: any[]) => any
+ ? T[K]
+ : Slot<T[K]>
+ }>
+ >
+
export type RawSlots = {
[name: string]: unknown
// manual render fn hint to skip forced children updates
): VNode
// functional component
-export function h<P, E extends EmitsOptions = {}>(
- type: FunctionalComponent<P, E>,
+export function h<
+ P,
+ E extends EmitsOptions = {},
+ S extends Record<string, any> = {}
+>(
+ type: FunctionalComponent<P, E, S>,
props?: (RawProps & P) | ({} extends P ? null : never),
children?: RawChildren | RawSlots
): VNode
defineEmits,
defineExpose,
defineOptions,
+ defineSlots,
withDefaults,
// internal
mergeDefaults,
RootRenderFunction
} from './renderer'
export type { RootHydrateFunction } from './hydration'
-export type { Slot, Slots } from './componentSlots'
+export type { Slot, Slots, SlotsType } from './componentSlots'
export type {
Prop,
PropType,
type _defineEmits = typeof defineEmits
type _defineExpose = typeof defineExpose
type _defineOptions = typeof defineOptions
+type _defineSlots = typeof defineSlots
type _withDefaults = typeof withDefaults
declare global {
const defineEmits: _defineEmits
const defineExpose: _defineExpose
const defineOptions: _defineOptions
+ const defineSlots: _defineSlots
const withDefaults: _withDefaults
}
warn,
ConcreteComponent,
ComponentOptions,
- ComponentInjectOptions
+ ComponentInjectOptions,
+ SlotsType
} from '@vue/runtime-core'
import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared'
import { hydrate, render } from '.'
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions,
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string
>(
Extends,
E,
EE,
+ S,
I,
II
> & { styles?: string[] }
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>,
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string
>(
Extends,
E,
EE,
+ S,
I,
II
> & { styles?: string[] }
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>,
EE extends string = string,
+ S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string
>(
Extends,
E,
EE,
+ S,
I,
II
> & { styles?: string[] }