Remove nightly and unstable-traits features in preparation for 1.75.

This commit is contained in:
Dario Nieuwenhuis
2023-11-29 17:23:48 +01:00
parent 384bad7bfa
commit c6989dfbca
127 changed files with 1971 additions and 2352 deletions

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-nrf-v$VERSION/embassy-nrf/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/src/"
features = ["nightly", "time", "defmt", "unstable-pac", "unstable-traits", "gpiote", "time-driver-rtc1"]
features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"]
flavors = [
{ regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
{ regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
@ -32,10 +32,7 @@ rt = [
time = ["dep:embassy-time"]
defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embassy-embedded-hal/defmt"]
# Enable nightly-only features
nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io-async", "embassy-embedded-hal/nightly"]
defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"]
# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`.
# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version.
@ -43,10 +40,6 @@ nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "em
# There are no plans to make this stable.
unstable-pac = []
# Implement embedded-hal 1.0 alpha traits.
# Implement embedded-hal-async traits if `nightly` is set as well.
unstable-traits = ["embedded-hal-1"]
nrf52805 = ["nrf52805-pac", "_nrf52"]
nrf52810 = ["nrf52810-pac", "_nrf52"]
nrf52811 = ["nrf52811-pac", "_nrf52"]
@ -98,13 +91,13 @@ embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2", optional = true}
embedded-hal-async = { version = "=1.0.0-rc.2", optional = true}
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" }
embedded-hal-async = { version = "=1.0.0-rc.2" }
embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.6.1", optional = true }
embedded-io-async = { version = "0.6.1" }
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
@ -114,7 +107,7 @@ critical-section = "1.1"
rand_core = "0.6.3"
fixed = "1.10.0"
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0", optional = true }
embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"
nrf52805-pac = { version = "0.12.0", optional = true }

View File

@ -607,7 +607,6 @@ impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> {
}
}
#[cfg(feature = "nightly")]
mod _embedded_io {
use super::*;

View File

@ -131,7 +131,6 @@ embassy_hal_internal::peripherals! {
QDEC,
}
#[cfg(feature = "nightly")]
impl_usb!(USBD, USBD, USBD);
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);

View File

@ -171,7 +171,6 @@ embassy_hal_internal::peripherals! {
I2S,
}
#[cfg(feature = "nightly")]
impl_usb!(USBD, USBD, USBD);
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);

View File

@ -174,7 +174,6 @@ embassy_hal_internal::peripherals! {
I2S,
}
#[cfg(feature = "nightly")]
impl_usb!(USBD, USBD, USBD);
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);

View File

@ -382,7 +382,6 @@ embassy_hal_internal::peripherals! {
P1_15,
}
#[cfg(feature = "nightly")]
impl_usb!(USBD, USBD, USBD);
impl_uarte!(SERIAL0, UARTE0, SERIAL0);

View File

@ -566,82 +566,77 @@ mod eh02 {
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
type Error = Infallible;
}
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
type Error = Infallible;
impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_high())
}
impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> {
type Error = Infallible;
}
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.set_high())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.set_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_high())
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
type Error = Infallible;
}
/// Implement [`InputPin`] for [`Flex`];
///
/// If the pin is not in input mode the result is unspecified.
impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.set_high())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.set_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_high())
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_low())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> {
type Error = Infallible;
}
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.set_high())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.set_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_high())
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
type Error = Infallible;
}
/// Implement [`InputPin`] for [`Flex`];
///
/// If the pin is not in input mode the result is unspecified.
impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(self.set_high())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(self.set_low())
}
}
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_high())
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_set_low())
}
}

View File

@ -490,70 +490,60 @@ mod eh02 {
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> {
type Error = Infallible;
}
impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> {
type Error = Infallible;
impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.pin.is_high())
}
impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> {
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.pin.is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.pin.is_low())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.pin.is_low())
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use super::*;
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_high().await)
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_low().await)
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_rising_edge().await)
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_falling_edge().await)
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_any_edge().await)
}
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_high().await)
}
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_high().await)
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_low().await)
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_low().await)
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_rising_edge().await)
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_rising_edge().await)
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_falling_edge().await)
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_falling_edge().await)
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_any_edge().await)
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_any_edge().await)
}
}
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_high().await)
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_low().await)
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_rising_edge().await)
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_falling_edge().await)
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
Ok(self.wait_for_any_edge().await)
}
}

View File

@ -1,6 +1,5 @@
#![no_std]
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
#![cfg_attr(feature = "nightly", allow(stable_features, unknown_lints, async_fn_in_trait))]
#![allow(async_fn_in_trait)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
@ -76,7 +75,6 @@ pub mod uarte;
feature = "nrf52833",
feature = "nrf52840"
))]
#[cfg(feature = "nightly")]
pub mod usb;
#[cfg(not(feature = "_nrf5340"))]
pub mod wdt;

View File

@ -585,7 +585,6 @@ impl<'d, T: Instance> NorFlash for Qspi<'d, T> {
}
}
#[cfg(feature = "nightly")]
mod _eh1 {
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};

View File

@ -495,72 +495,61 @@ mod eh02 {
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl embedded_hal_1::spi::Error for Error {
fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
match *self {
Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other,
}
}
}
impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spim<'d, T> {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_transfer(words, &[])
}
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(words)
}
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.blocking_transfer(read, write)
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_transfer_in_place(words)
impl embedded_hal_1::spi::Error for Error {
fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
match *self {
Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other,
}
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spim<'d, T> {
type Error = Error;
}
use super::*;
impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
async fn flush(&mut self) -> Result<(), Error> {
Ok(())
}
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_transfer(words, &[])
}
async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
self.read(words).await
}
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(words)
}
async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
self.write(data).await
}
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.blocking_transfer(read, write)
}
async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
self.transfer(rx, tx).await
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_transfer_in_place(words)
}
}
async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
self.transfer_in_place(words).await
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
async fn flush(&mut self) -> Result<(), Error> {
Ok(())
}
async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
self.read(words).await
}
async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
self.write(data).await
}
async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
self.transfer(rx, tx).await
}
async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
self.transfer_in_place(words).await
}
}

View File

@ -810,81 +810,72 @@ mod eh02 {
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl embedded_hal_1::i2c::Error for Error {
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
match *self {
Self::TxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other,
Self::AddressNack => {
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
}
Self::DataNack => {
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Data)
}
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
impl embedded_hal_1::i2c::Error for Error {
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
match *self {
Self::TxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other,
Self::AddressNack => {
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
}
}
}
impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> {
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, buffer)
}
fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, buffer)
}
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, wr_buffer, rd_buffer)
}
fn transaction<'a>(
&mut self,
_address: u8,
_operations: &mut [embedded_hal_1::i2c::Operation<'a>],
) -> Result<(), Self::Error> {
todo!();
Self::DataNack => {
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Data)
}
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
}
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use super::*;
impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.read(address, read).await
}
impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> {
type Error = Error;
}
async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.write(address, write).await
}
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.write_read(address, write, read).await
}
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> {
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, buffer)
}
async fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
let _ = address;
let _ = operations;
todo!()
}
fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, buffer)
}
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, wr_buffer, rd_buffer)
}
fn transaction<'a>(
&mut self,
_address: u8,
_operations: &mut [embedded_hal_1::i2c::Operation<'a>],
) -> Result<(), Self::Error> {
todo!();
}
}
impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.read(address, read).await
}
async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.write(address, write).await
}
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.write_read(address, write, read).await
}
async fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
let _ = address;
let _ = operations;
todo!()
}
}