From 13710c68616cf643d3cdfd69e5f39b2dc5a801b4 Mon Sep 17 00:00:00 2001 From: acdlite Date: Thu, 18 Apr 2024 17:42:21 +0000 Subject: [PATCH] Support writing to this.refs from userspace (#28867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the `refs` property of a class component instance was read-only by user code — only React could write to it, and until/unless a string ref was used, it pointed to a shared empty object that was frozen in dev to prevent userspace mutations. Because string refs are deprecated, we want users to be able to codemod all their string refs to callback refs. The safest way to do this is to output a callback ref that assigns to `this.refs`. So to support this, we need to make `this.refs` writable by userspace. DiffTrain build for commit https://github.com/facebook/react/commit/ea24427d16f3ac9b0f3bb45cdc7919ac208130c9. --- .../cjs/ReactTestRenderer-dev.js | 5 ++--- .../cjs/ReactTestRenderer-prod.js | 7 +++---- .../cjs/ReactTestRenderer-profiling.js | 7 +++---- .../js/RKJSModules/vendor/react/cjs/React-dev.js | 16 +++++----------- .../RKJSModules/vendor/react/cjs/React-prod.js | 11 +++++------ .../vendor/react/cjs/React-profiling.js | 11 +++++------ .../Libraries/Renderer/REVISION | 2 +- .../implementations/ReactFabric-dev.fb.js | 5 ++--- .../implementations/ReactFabric-prod.fb.js | 7 +++---- .../implementations/ReactFabric-profiling.fb.js | 7 +++---- .../ReactNativeRenderer-dev.fb.js | 5 ++--- .../ReactNativeRenderer-prod.fb.js | 7 +++---- .../ReactNativeRenderer-profiling.fb.js | 7 +++---- 13 files changed, 40 insertions(+), 57 deletions(-) diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js index e23f78a77d..6a1842e516 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<1af14f0d0942bd1e022dac734e776b15>> */ "use strict"; @@ -12589,7 +12589,6 @@ if (__DEV__) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; @@ -26673,7 +26672,7 @@ if (__DEV__) { return root; } - var ReactVersion = "19.0.0-canary-a47ffde4"; + var ReactVersion = "19.0.0-canary-4a670971"; /* * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js index 15d6f529db..4fc680d3d3 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -3426,7 +3426,6 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; "object" === typeof contextType && null !== contextType @@ -9144,7 +9143,7 @@ var devToolsConfig$jscomp$inline_1019 = { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "19.0.0-canary-7a48fce4", + version: "19.0.0-canary-3c5c4140", rendererPackageName: "react-test-renderer" }; var internals$jscomp$inline_1238 = { @@ -9175,7 +9174,7 @@ var internals$jscomp$inline_1238 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "19.0.0-canary-7a48fce4" + reconcilerVersion: "19.0.0-canary-3c5c4140" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1239 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js index 7889255683..d2a5b42e07 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<9206ca0f6781a4c840d6d393f26b3429>> + * @generated SignedSource<<2efa00521669a237ba088981baf581b8>> */ "use strict"; @@ -3584,7 +3584,6 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; "object" === typeof contextType && null !== contextType @@ -9760,7 +9759,7 @@ var devToolsConfig$jscomp$inline_1101 = { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "19.0.0-canary-39a6938a", + version: "19.0.0-canary-dec118c3", rendererPackageName: "react-test-renderer" }; (function (internals) { @@ -9804,7 +9803,7 @@ var devToolsConfig$jscomp$inline_1101 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "19.0.0-canary-39a6938a" + reconcilerVersion: "19.0.0-canary-dec118c3" }); exports._Scheduler = Scheduler; exports.act = act; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js index e6ce3bb8a1..cb256ac794 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<150980e4b77b12c241c9997159b4f67a>> + * @generated SignedSource<> */ "use strict"; @@ -26,7 +26,7 @@ if (__DEV__) { } var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - var ReactVersion = "19.0.0-canary-a13a0c2f"; + var ReactVersion = "19.0.0-canary-d59b7713"; // ATTENTION // When adding new symbols to this file, @@ -299,20 +299,14 @@ if (__DEV__) { var assign = Object.assign; - var emptyObject = {}; - - { - Object.freeze(emptyObject); - } /** * Base class helpers for the updating state of a component. */ function Component(props, context, updater) { this.props = props; - this.context = context; // If a component has string refs, we will assign a different object later. - - this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the + this.context = context; + this.refs = {}; // We initialize the default updater but the real one gets injected by the // renderer. this.updater = updater || ReactNoopUpdateQueue; @@ -429,7 +423,7 @@ if (__DEV__) { this.props = props; this.context = context; // If a component has string refs, we will assign a different object later. - this.refs = emptyObject; + this.refs = {}; this.updater = updater || ReactNoopUpdateQueue; } diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js index 2347230b31..3eb0e494f0 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<00252b7815c38ef0d757b44717a43f7d>> + * @generated SignedSource<<4623f2323ff9fe23a59f41063e37036d>> */ "use strict"; @@ -46,12 +46,11 @@ var ReactNoopUpdateQueue = { enqueueReplaceState: function () {}, enqueueSetState: function () {} }, - assign = Object.assign, - emptyObject = {}; + assign = Object.assign; function Component(props, context, updater) { this.props = props; this.context = context; - this.refs = emptyObject; + this.refs = {}; this.updater = updater || ReactNoopUpdateQueue; } Component.prototype.isReactComponent = {}; @@ -74,7 +73,7 @@ ComponentDummy.prototype = Component.prototype; function PureComponent(props, context, updater) { this.props = props; this.context = context; - this.refs = emptyObject; + this.refs = {}; this.updater = updater || ReactNoopUpdateQueue; } var pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()); @@ -679,4 +678,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.0.0-canary-3277b133"; +exports.version = "19.0.0-canary-43e619b6"; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js index 1c52dbc17b..7150f114fb 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<9fd3393509037fbe670735ccea6d8cca>> + * @generated SignedSource<<6bf80ec383f6cf4c2e8d203cf6a830b0>> */ "use strict"; @@ -50,12 +50,11 @@ var ReactNoopUpdateQueue = { enqueueReplaceState: function () {}, enqueueSetState: function () {} }, - assign = Object.assign, - emptyObject = {}; + assign = Object.assign; function Component(props, context, updater) { this.props = props; this.context = context; - this.refs = emptyObject; + this.refs = {}; this.updater = updater || ReactNoopUpdateQueue; } Component.prototype.isReactComponent = {}; @@ -78,7 +77,7 @@ ComponentDummy.prototype = Component.prototype; function PureComponent(props, context, updater) { this.props = props; this.context = context; - this.refs = emptyObject; + this.refs = {}; this.updater = updater || ReactNoopUpdateQueue; } var pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()); @@ -683,7 +682,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.0.0-canary-52747c26"; +exports.version = "19.0.0-canary-c3e8564d"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION index b7d32f412a..caf9c67854 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION @@ -1 +1 @@ -0061ca6cf47c5124d2ebe708481fb03da9e8e267 +ea24427d16f3ac9b0f3bb45cdc7919ac208130c9 diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index 59246472fe..3726f237b8 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<84d884f07a1d5851f53652012b257860>> + * @generated SignedSource<<69452b089b0732ebffeaf4ae565a8ac2>> */ "use strict"; @@ -16131,7 +16131,6 @@ to return true:wantsResponderID| | var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; @@ -30296,7 +30295,7 @@ to return true:wantsResponderID| | return root; } - var ReactVersion = "19.0.0-canary-adfb7d73"; + var ReactVersion = "19.0.0-canary-385c1224"; /* * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js index d42407ff20..0623832e5a 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<13b0be8da9b49fcd1f29069f699207ea>> */ "use strict"; @@ -4995,7 +4995,6 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; "object" === typeof contextType && null !== contextType @@ -10602,7 +10601,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1099 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "19.0.0-canary-7f7baf16", + version: "19.0.0-canary-7feb98a8", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10645,7 +10644,7 @@ var internals$jscomp$inline_1366 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "19.0.0-canary-7f7baf16" + reconcilerVersion: "19.0.0-canary-7feb98a8" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1367 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js index b8bf91b074..68aa846a61 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<64acec7be24561ecbf6d2eaf55e55d0a>> + * @generated SignedSource<> */ "use strict"; @@ -5187,7 +5187,6 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; "object" === typeof contextType && null !== contextType @@ -11307,7 +11306,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1179 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "19.0.0-canary-ef6bcf29", + version: "19.0.0-canary-e320aa3b", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -11363,7 +11362,7 @@ var roots = new Map(), scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "19.0.0-canary-ef6bcf29" + reconcilerVersion: "19.0.0-canary-e320aa3b" }); exports.createPortal = function (children, containerTag) { return createPortal$1( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index 4dcdf67ad4..fcd681ceb3 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -16402,7 +16402,6 @@ to return true:wantsResponderID| | var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; @@ -30750,7 +30749,7 @@ to return true:wantsResponderID| | return root; } - var ReactVersion = "19.0.0-canary-ad24d706"; + var ReactVersion = "19.0.0-canary-22e6f306"; /* * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js index 5ee88e7cd9..e3ec52daf1 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<40e33e67d4c6fd0373352fbe892a02dc>> + * @generated SignedSource<> */ "use strict"; @@ -5048,7 +5048,6 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; "object" === typeof contextType && null !== contextType @@ -10824,7 +10823,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1168 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "19.0.0-canary-7fc44ecb", + version: "19.0.0-canary-21664510", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10867,7 +10866,7 @@ var internals$jscomp$inline_1452 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "19.0.0-canary-7fc44ecb" + reconcilerVersion: "19.0.0-canary-21664510" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1453 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js index 836fb391c1..c6d0b18cba 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<133502ac169bad393685ab94706b7e59>> */ "use strict"; @@ -5240,7 +5240,6 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = {}; initializeUpdateQueue(workInProgress); var contextType = ctor.contextType; "object" === typeof contextType && null !== contextType @@ -11530,7 +11529,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1248 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "19.0.0-canary-b6bdb4e2", + version: "19.0.0-canary-b8a8669d", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -11586,7 +11585,7 @@ var roots = new Map(), scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "19.0.0-canary-b6bdb4e2" + reconcilerVersion: "19.0.0-canary-b8a8669d" }); exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { computeComponentStackForErrorReporting: function (reactTag) {