esphome_native_api/
esphomeapi.rs

1use crate::frame::construct_frame;
2use crate::frame::to_encrypted_frame;
3use crate::frame::to_unencrypted_frame;
4use crate::packet_encrypted;
5use crate::parser;
6use crate::parser::ProtoMessage;
7use crate::proto::version_2025_12_1::AuthenticationResponse;
8use crate::proto::version_2025_12_1::DeviceInfoResponse;
9use crate::proto::version_2025_12_1::DisconnectResponse;
10use crate::proto::version_2025_12_1::HelloResponse;
11use crate::proto::version_2025_12_1::PingResponse;
12use base64::prelude::*;
13use byteorder::BigEndian;
14use byteorder::ByteOrder;
15use constant_time_eq::constant_time_eq;
16use log::debug;
17use log::error;
18use log::info;
19use log::trace;
20use log::warn;
21use noise_protocol::CipherState;
22use noise_protocol::ErrorKind;
23use noise_protocol::HandshakeState;
24use noise_protocol::patterns::noise_nn_psk0;
25use noise_rust_crypto::ChaCha20Poly1305;
26use noise_rust_crypto::Sha256;
27use noise_rust_crypto::X25519;
28use std::sync::Arc;
29use std::sync::atomic::AtomicBool;
30use tokio::io::{AsyncReadExt, AsyncWriteExt};
31use tokio::net::TcpStream;
32use tokio::sync::Mutex;
33use tokio::sync::broadcast;
34use typed_builder::TypedBuilder;
35
36#[derive(Debug)]
37pub(crate) enum EncryptionState {
38    Uninitialized,
39    ClientHandshake,
40    ServerHello,
41    Initialized,
42    Failure,
43}
44
45#[derive(TypedBuilder)]
46pub struct EspHomeApi {
47    // Private fields
48    #[builder(default=Arc::new(AtomicBool::new(false)))]
49    pub(crate) password_authenticated: Arc<AtomicBool>,
50    #[builder(default=Arc::new(AtomicBool::new(false)))]
51    pub(crate) key_authenticated: Arc<AtomicBool>,
52
53    #[builder(default=Arc::new(AtomicBool::new(false)))]
54    pub(crate) encrypted_api: Arc<AtomicBool>,
55
56    #[builder(default=Arc::new(Mutex::new(EncryptionState::Uninitialized)))]
57    pub(crate) encryption_state: Arc<Mutex<EncryptionState>>,
58
59    #[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
60    pub(crate) handshake_state:
61        Arc<Mutex<Option<HandshakeState<X25519, ChaCha20Poly1305, Sha256>>>>,
62    #[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
63    pub(crate) encrypt_cypher: Arc<Mutex<Option<CipherState<ChaCha20Poly1305>>>>,
64    #[builder(default=Arc::new(Mutex::new(None)), setter(skip))]
65    pub(crate) decrypt_cypher: Arc<Mutex<Option<CipherState<ChaCha20Poly1305>>>>,
66
67    name: String,
68
69    #[builder(default = None, setter(strip_option(fallback=password_opt)))]
70    #[deprecated(note = "https://esphome.io/components/api.html#configuration-variables")]
71    password: Option<String>,
72    #[builder(default = None, setter(strip_option(fallback=encryption_key_opt)))]
73    encryption_key: Option<String>,
74
75    #[builder(default = 1)]
76    api_version_major: u32,
77    #[builder(default = 10)]
78    api_version_minor: u32,
79    #[builder(default="Rust: esphome-native-api".to_string())]
80    server_info: String,
81
82    #[builder(default = None, setter(strip_option(fallback=friendly_name_opt)))]
83    friendly_name: Option<String>,
84
85    #[builder(default = None, setter(strip_option(fallback=mac_opt)))]
86    mac: Option<String>,
87
88    #[builder(default = None, setter(strip_option(fallback=model_opt)))]
89    model: Option<String>,
90
91    #[builder(default = None, setter(strip_option(fallback=manufacturer_opt)))]
92    manufacturer: Option<String>,
93    #[builder(default = None, setter(strip_option(fallback=suggested_area_opt)))]
94    suggested_area: Option<String>,
95    #[builder(default = None, setter(strip_option(fallback=bluetooth_mac_address_opt)))]
96    bluetooth_mac_address: Option<String>,
97
98    #[builder(default = None, setter(strip_option(fallback=project_name_opt)))]
99    project_name: Option<String>,
100
101    #[builder(default = None, setter(strip_option(fallback=project_version_opt)))]
102    project_version: Option<String>,
103    #[builder(default = None, setter(strip_option(fallback=compilation_time_opt)))]
104    compilation_time: Option<String>,
105
106    #[builder(default = 0)]
107    legacy_bluetooth_proxy_version: u32,
108    #[builder(default = 0)]
109    bluetooth_proxy_feature_flags: u32,
110    #[builder(default = 0)]
111    legacy_voice_assistant_version: u32,
112    #[builder(default = 0)]
113    voice_assistant_feature_flags: u32,
114
115    #[builder(default = "2025.4.0".to_string())]
116    esphome_version: String,
117}
118
119/// Handles the EspHome Api, with encryption etc.
120impl EspHomeApi {
121    /// Starts the server and returns a broadcast channel for messages, and a
122    /// broadcast receiver for all messages not handled by the abstraction
123    pub async fn start(
124        &mut self,
125        tcp_stream: TcpStream,
126    ) -> Result<
127        (
128            broadcast::Sender<ProtoMessage>,
129            broadcast::Receiver<ProtoMessage>,
130        ),
131        Box<dyn std::error::Error>,
132    > {
133        if self.password.is_none() && self.encryption_key.is_none() {
134            self.password_authenticated
135                .store(true, std::sync::atomic::Ordering::Relaxed);
136        }
137
138        // Channel for direct answers (prioritized when sending)
139        let (answer_messages_tx, mut answer_messages_rx) = broadcast::channel::<ProtoMessage>(16);
140        // Channel for normal messages (e.g. state updates)
141        let (messages_tx, mut messages_rx) = broadcast::channel::<ProtoMessage>(16);
142        let (outgoing_messages_tx, mut outgoing_messages_rx) =
143            broadcast::channel::<ProtoMessage>(16);
144
145        // Asynchronously wait for an inbound socket.
146        let (mut read, mut write) = tcp_stream.into_split();
147
148        let device_info = DeviceInfoResponse {
149            api_encryption_supported: self.encryption_key.is_some(),
150            uses_password: self.password.is_some(),
151            name: self.name.clone(),
152            mac_address: self.mac.clone().unwrap_or_default(),
153            esphome_version: self.esphome_version.clone(),
154            compilation_time: self.compilation_time.clone().unwrap_or_default(),
155            model: self.model.clone().unwrap_or_default(),
156            has_deep_sleep: false,
157            project_name: self.project_name.clone().unwrap_or_default(),
158            project_version: self.project_version.clone().unwrap_or_default(),
159            webserver_port: 0,
160            // See https://github.com/esphome/aioesphomeapi/blob/c1fee2f4eaff84d13ca71996bb272c28b82314fc/aioesphomeapi/model.py#L154
161            legacy_bluetooth_proxy_version: self.legacy_bluetooth_proxy_version,
162            bluetooth_proxy_feature_flags: self.bluetooth_proxy_feature_flags,
163            manufacturer: self.manufacturer.clone().unwrap_or_default(),
164            friendly_name: self.friendly_name.clone().unwrap_or(self.name.clone()),
165            legacy_voice_assistant_version: self.legacy_voice_assistant_version,
166            voice_assistant_feature_flags: self.voice_assistant_feature_flags,
167            suggested_area: self.suggested_area.clone().unwrap_or_default(),
168            bluetooth_mac_address: self.bluetooth_mac_address.clone().unwrap_or_default(),
169            areas: vec![],
170            devices: vec![],
171            area: None,
172            zwave_proxy_feature_flags:0,
173            zwave_home_id: 0
174        };
175
176        if self.encryption_key.is_some() {
177            debug!("Encryption enabled");
178            self.encrypted_api
179                .store(true, std::sync::atomic::Ordering::Relaxed);
180        }
181
182        let hello_response = HelloResponse {
183            api_version_major: self.api_version_major,
184            api_version_minor: self.api_version_minor,
185            server_info: self.server_info.clone(),
186            name: self.name.clone(),
187        };
188        let password_clone = self.password.clone();
189        let encrypted_api = self.encrypted_api.clone();
190        let encrypt_cypher_clone = self.encrypt_cypher.clone();
191        let decrypt_cypher_clone = self.decrypt_cypher.clone();
192        let encryption_state = self.encryption_state.clone();
193        let handshake_state_clone = self.handshake_state.clone();
194        let answer_messages_tx_clone = answer_messages_tx.clone();
195        let messages_tx_clone = messages_tx.clone();
196        tokio::spawn(async move {
197            tokio::select! {
198                _ = answer_messages_tx_clone.closed() => {
199                    info!("CLOSED");
200                }
201                _ = messages_tx_clone.closed() => {
202                    info!("CLOSED");
203                }
204            };
205        });
206
207        // Write Loop
208        tokio::spawn(async move {
209            let mut disconnect = false;
210            loop {
211                let mut answer_buf: Vec<u8> = vec![];
212                let answer_message: ProtoMessage;
213                let encryption = encrypted_api.load(std::sync::atomic::Ordering::Relaxed);
214
215                // If encryption is enabled we have to make sure initialization messages are send before any custom messages
216                let mut initialized = false;
217                {
218                    let mut encryption_state_changer = encryption_state.lock().await;
219                    match *encryption_state_changer {
220                        EncryptionState::Initialized => {
221                            initialized = true;
222                        }
223                        _ => {
224                            initialized = true;
225                        }
226                    }
227                }
228
229                // Wait for any new message
230                if encryption && !initialized {
231                    answer_message = answer_messages_rx.recv().await.unwrap();
232                } else {
233                    tokio::select! {
234                        biased; // Poll answer_messages_rx first
235                        message = answer_messages_rx.recv() => {
236                            answer_message = message.unwrap();
237                        }
238                        message = messages_rx.recv() => {
239                            answer_message = message.unwrap();
240                        }
241                    };
242                }
243
244                if encryption {
245                    {
246                        let mut first_run = false;
247                        let mut encryption_state_changer = encryption_state.lock().await;
248                        match *encryption_state_changer {
249                            EncryptionState::ClientHandshake => {
250                                let mut message_server_hello: Vec<u8> = Vec::new();
251
252                                let encryption_protocol: Vec<u8> = vec![1];
253                                let node_name = b"test_node";
254                                let node_mac_address = b"00:00:00:00:00:01";
255                                message_server_hello.extend(encryption_protocol);
256                                message_server_hello.extend(node_name);
257                                message_server_hello.extend(b"\0");
258                                message_server_hello.extend(node_mac_address);
259                                message_server_hello.extend(b"\0");
260
261                                let len_u16 = message_server_hello.len() as u16;
262                                let len_bytes = len_u16.to_be_bytes();
263                                let length: Vec<u8> = vec![len_bytes[0], len_bytes[1]];
264
265                                let mut hello_frame = vec![1];
266                                hello_frame.extend(length);
267                                hello_frame.extend(message_server_hello);
268
269                                debug!("Sending server hello: {:02X?}", &hello_frame);
270                                write
271                                    .write_all(&hello_frame)
272                                    .await
273                                    .expect("failed to write encrypted response");
274                                write.flush().await.expect("failed to flush server hello");
275
276                                *encryption_state_changer = EncryptionState::ServerHello;
277                                first_run = true;
278                            }
279                            _ => {}
280                        }
281
282                        match *encryption_state_changer {
283                            EncryptionState::ServerHello => {
284                                let out: Vec<u8>;
285                                let mut handshake_state_change = handshake_state_clone.lock().await;
286
287                                if handshake_state_change.is_none() {
288                                    *encryption_state_changer = EncryptionState::Failure;
289                                } else {
290                                    let handshake_state =
291                                        (*handshake_state_change).as_mut().unwrap();
292
293                                    out = handshake_state.write_message_vec(b"").unwrap();
294                                    {
295                                        let mut encrypt_cipher_changer =
296                                            encrypt_cypher_clone.lock().await;
297                                        let mut decrypt_cipher_changer =
298                                            decrypt_cypher_clone.lock().await;
299                                        let (decrypt_cipher, encrypt_cipher) =
300                                            handshake_state.get_ciphers();
301                                        *encrypt_cipher_changer = Some(encrypt_cipher);
302                                        *decrypt_cipher_changer = Some(decrypt_cipher);
303                                    }
304
305                                    let mut message_handshake = vec![0];
306                                    message_handshake.extend(out);
307
308                                    let len_u16 = message_handshake.len() as u16;
309                                    let len_bytes = len_u16.to_be_bytes();
310                                    let length: Vec<u8> = vec![len_bytes[0], len_bytes[1]];
311
312                                    let mut encrypted_frame = vec![1];
313                                    encrypted_frame.extend(length);
314                                    encrypted_frame.extend(message_handshake);
315
316                                    debug!("Sending handshake: {:02X?}", &encrypted_frame);
317                                    write
318                                        .write_all(&encrypted_frame)
319                                        .await
320                                        .expect("failed to write encrypted response");
321
322                                    *encryption_state_changer = EncryptionState::Initialized;
323                                }
324                            }
325                            _ => {}
326                        }
327                        match *encryption_state_changer {
328                            EncryptionState::Initialized => {
329                                if first_run {
330                                    continue;
331                                }
332                                debug!("Answer message: {:?}", answer_message);
333                                // Use normal messaging
334                                {
335                                    let mut encrypt_cipher_changer =
336                                        encrypt_cypher_clone.lock().await;
337                                    let encrypted_frame = to_encrypted_frame(
338                                        &answer_message,
339                                        &mut *encrypt_cipher_changer.as_mut().unwrap(),
340                                    )
341                                    .unwrap();
342
343                                    answer_buf = [answer_buf, encrypted_frame].concat();
344                                }
345                            }
346                            _ => {
347                                let packet = [
348                                    [1].to_vec(),
349                                    "Only key encryption is enabled".as_bytes().to_vec(),
350                                ]
351                                .concat();
352                                answer_buf = construct_frame(&packet, true).unwrap();
353                                disconnect = true;
354                            }
355                        }
356                        match *encryption_state_changer {
357                            EncryptionState::Failure => {
358                                error!("Encrypted API Failure. Disconnecting.");
359                                let packet =
360                                    [[1].to_vec(), "Handshake MAC failure".as_bytes().to_vec()]
361                                        .concat();
362                                answer_buf = construct_frame(&packet, true).unwrap();
363                                disconnect = true;
364                                // answer_buf = [answer_buf, failure_buffer].concat();
365                            }
366                            _ => {}
367                        }
368                    }
369                } else {
370                    debug!("Answer message: {:?}", answer_message);
371                    answer_buf =
372                        [answer_buf, to_unencrypted_frame(&answer_message).unwrap()].concat();
373                }
374
375                match answer_message {
376                    ProtoMessage::DisconnectResponse(_) => {
377                        disconnect = true;
378                    }
379                    _ => {}
380                }
381
382                trace!("TCP Send: {:02X?}", &answer_buf);
383
384                match write.write_all(&answer_buf).await {
385                    Err(err) => {
386                        error!("Failed to write data to socket: {:?}", err);
387                        break;
388                    }
389                    _ => {}
390                }
391
392                write.flush().await.expect("failed to flush data to socket");
393
394                if disconnect {
395                    debug!("Disconnecting");
396                match write.shutdown().await {
397                    Err(err) => {
398                        error!("failed to shutdown socket: {:?}", err);
399                        break;
400                    },
401                    _ => break
402                }
403            }
404            }
405        });
406
407        // Clone all necessary data before spawning the task
408        let answer_messages_tx_clone = answer_messages_tx.clone();
409        let handshake_state_clone = self.handshake_state.clone();
410        let encryption_state = self.encryption_state.clone();
411        let encryption_key = self.encryption_key.clone();
412        let encrypted_api = self.encrypted_api.clone();
413        let decrypt_cypher_clone = self.decrypt_cypher.clone();
414        let password_authenticated = self.password_authenticated.clone();
415        let key_authenticated = self.key_authenticated.clone();
416
417        // Read Loop
418        tokio::spawn(async move {
419            let mut buf = vec![0; 1024];
420
421            loop {
422                let n = read
423                    .read(&mut buf)
424                    .await
425                    .expect("failed to read data from socket");
426
427                if n == 0 {
428                    return;
429                }
430
431                trace!("TCP Receive: {:02X?}", &buf[0..n]);
432
433                let mut cursor = 0;
434
435                while cursor < n {
436                    // Ignore first byte
437                    // Get Length of packet
438
439                    let message;
440                    let preamble = buf[cursor] as usize;
441                    trace!("Cursor: {:?}", &cursor);
442                    // trace!("n: {:?}", &n);
443
444                    match preamble {
445                        0 => {
446                            trace!("Cleartext message");
447                            // Cleartext
448
449                            // TODO: use dynamic length bits
450                            let len = buf[cursor + 1] as usize;
451                            message = cleartext_frame_to_message(
452                                &buf[cursor + 2..cursor + 3 + len].to_vec(),
453                            )
454                            .unwrap();
455                            cursor += 3 + len;
456
457                            match &message {
458                                ProtoMessage::HelloRequest(hello_request) => {
459                                    debug!("HelloRequest: {:?}", hello_request);
460
461                                    answer_messages_tx_clone
462                                        .send(ProtoMessage::HelloResponse(hello_response.clone()))
463                                        .unwrap();
464                                    continue;
465                                }
466                                _ => {}
467                            }
468                        }
469                        1 => {
470                            trace!("Encrypted message");
471
472                            let mut encryption_state_changer = encryption_state.lock().await;
473                            match *encryption_state_changer {
474                                EncryptionState::Uninitialized => {
475                                    trace!("Encryption State: Uninitialized");
476
477                                    encrypted_api.store(true, std::sync::atomic::Ordering::Relaxed);
478
479                                    // Similar to https://github.com/esphome/aioesphomeapi/blob/60bcd1698dd622aeac6f4b5ec448bab0e3467c4f/aioesphomeapi/_frame_helper/noise.py#L248C17-L255
480                                    let mut handshake_state: HandshakeState<
481                                        X25519,
482                                        ChaCha20Poly1305,
483                                        Sha256,
484                                    > = HandshakeState::new(
485                                        noise_nn_psk0(),
486                                        false,
487                                        // NEXT: This is somehow set from the first api message?
488                                        b"NoiseAPIInit\0\0",
489                                        None,
490                                        None,
491                                        None,
492                                        None,
493                                    );
494
495                                    encrypted_api.store(true, std::sync::atomic::Ordering::Relaxed);
496                                    let noise_psk = BASE64_STANDARD
497                                        .decode(encryption_key.as_ref().unwrap())
498                                        .unwrap();
499
500                                    handshake_state.push_psk(&noise_psk);
501                                    match handshake_state.read_message_vec(&buf[3 + 3 + 1..n]) {
502                                        Ok(_) => {
503                                            {
504                                                let mut mutex_changer =
505                                                    handshake_state_clone.lock().await;
506                                                *mutex_changer = Option::Some(handshake_state);
507                                            }
508                                        }
509                                        Err(e) => {
510                                            match e.kind() {
511                                                // Only warn here. The error will be handled in the send loop
512                                                ErrorKind::Decryption => {
513                                                    warn!("Decryption failed: {}", e);
514                                                }
515                                                _ => {
516                                                    debug!("Failed to read message: {}", e);
517                                                }
518                                            }
519                                        }
520                                    }
521
522                                    // This Message is never send but needed to trigger sending the SERVER_HELLO
523                                    answer_messages_tx_clone
524                                        .send(ProtoMessage::HelloResponse(
525                                            hello_response.clone(),
526                                        ))
527                                        .unwrap();
528                                    *encryption_state_changer =
529                                        EncryptionState::ClientHandshake;
530                                    cursor += n;
531                                    continue;
532                                }
533                                EncryptionState::Initialized => {
534                                    trace!("Encryption State: Initialized");
535                                    let len =
536                                        BigEndian::read_u16(&buf[cursor + 1..cursor + 3]) as usize;
537                                    // trace!("Length: {:?}", &len);
538                                    let decrypted_message = &buf[cursor + 3..cursor + len + 3];
539                                    // trace!("To decrypt message: {:02X?}", &decrypted_message);
540                                    {
541                                        let mut decrypt_cipher_changer =
542                                            decrypt_cypher_clone.lock().await;
543                                        message = packet_encrypted::packet_to_message(
544                                            decrypted_message,
545                                            &mut *decrypt_cipher_changer.as_mut().unwrap(),
546                                        )
547                                        .unwrap();
548                                    }
549                                    key_authenticated
550                                        .store(true, std::sync::atomic::Ordering::Relaxed);
551
552                                    cursor += 3 + len;
553                                }
554                                _ => {
555                                    debug!(
556                                        "Wrong encryption state: {:?}",
557                                        *encryption_state_changer
558                                    );
559                                    return;
560                                }
561                            }
562                        }
563                        _ => {
564                            debug!("Marker byte invalid: {}", preamble);
565                            return;
566                        }
567                    }
568
569                    // Initialization Messages (unauthenticated)
570                    match &message {
571                        ProtoMessage::HelloRequest(_) => {
572                                answer_messages_tx_clone
573                                    .send(ProtoMessage::HelloResponse(
574                                        hello_response.clone(),
575                                    ))
576                                    .unwrap();
577                        }
578                        ProtoMessage::AuthenticationRequest(connect_request) => {
579                            debug!("AuthenticationRequest: {:?}", connect_request);
580                            let mut valid = false;
581                            if encryption_key.is_some() {
582                                valid = true;
583                            } else {
584                                if let Some(password) = password_clone.clone() {
585                                    valid = constant_time_eq(
586                                        connect_request.password.as_bytes(),
587                                        password.as_bytes(),
588                                    );
589                                }
590                            }
591
592                            password_authenticated
593                                .store(valid, std::sync::atomic::Ordering::Relaxed);
594                            let response_message = AuthenticationResponse {
595                                invalid_password: !valid,
596                            };
597                            debug!("AuthenticationResponse: {:?}", response_message);
598                            answer_messages_tx_clone
599                                .send(ProtoMessage::AuthenticationResponse(response_message))
600                                .unwrap();
601                            continue;
602                        }
603                        ProtoMessage::DisconnectRequest(disconnect_request) => {
604                            debug!("DisconnectRequest: {:?}", disconnect_request);
605                            let response_message = DisconnectResponse {};
606                            answer_messages_tx_clone
607                                .send(ProtoMessage::DisconnectResponse(response_message))
608                                .unwrap();
609                            continue;
610                        }
611                        _ => {}
612                    }
613                    let auth_test = key_authenticated.load(std::sync::atomic::Ordering::Relaxed)
614                        || password_authenticated.load(std::sync::atomic::Ordering::Relaxed);
615                    info!("Authenticated: {}", auth_test);
616
617                    if !auth_test {
618                        answer_messages_tx_clone
619                            .send(ProtoMessage::DisconnectResponse(DisconnectResponse {}))
620                            .unwrap();
621                        continue;
622                    }
623
624                    // Authenticated Messages
625                    match &message {
626                        ProtoMessage::PingRequest(ping_request) => {
627                            debug!("PingRequest: {:?}", ping_request);
628                            let response_message = PingResponse {};
629                            answer_messages_tx_clone
630                                .send(ProtoMessage::PingResponse(response_message))
631                                .unwrap();
632                        }
633                        ProtoMessage::DeviceInfoRequest(device_info_request) => {
634                            debug!("DeviceInfoRequest: {:?}", device_info_request);
635                            answer_messages_tx_clone
636                                .send(ProtoMessage::DeviceInfoResponse(device_info.clone()))
637                                .unwrap();
638                        }
639                        // Handled above
640                        ProtoMessage::HelloRequest(_) => {}
641                        message => {
642                            outgoing_messages_tx.send(message.clone()).unwrap();
643                        }
644                    }
645                }
646            }
647        });
648
649        Ok((messages_tx.clone(), outgoing_messages_rx))
650    }
651}
652
653#[cfg(test)]
654mod tests {
655    // Note this useful idiom: importing names from outer (for mod tests) scope.
656    use super::*;
657
658    #[test]
659    fn test_basic_server_instantiation() {
660        EspHomeApi::builder()
661            .name("test_device".to_string())
662            .build();
663    }
664}
665
666pub fn cleartext_frame_to_message(
667    buffer: &[u8],
668) -> Result<ProtoMessage, Box<dyn std::error::Error>> {
669    let message_type = buffer[0] as usize;
670    let packet_content = &buffer[1..];
671    debug!("Message type: {}", message_type);
672    debug!("Message: {:02X?}", packet_content);
673    Ok(parser::parse_proto_message(message_type, &packet_content).unwrap())
674}