diff --git a/src/bot/filters/message_fitlers.rs b/src/bot/filters/message_fitlers.rs
index f2d973d20848cffd4328f954b429c54b674f109f..6533d4ae30e61d713a7915cc9cc4ede76d74057a 100644
--- a/src/bot/filters/message_fitlers.rs
+++ b/src/bot/filters/message_fitlers.rs
@@ -1,4 +1,5 @@
 use grammers_client::Update;
+use regex::Regex;
 
 use crate::utils::messages::get_message;
 
@@ -31,9 +32,14 @@ pub struct ExcludedChatsFilter(pub Vec<i64>);
 #[derive(Clone)]
 pub struct MessageDirectionFilter(pub MessageDirection);
 
+/// Filters text by predicate.
 #[derive(Clone)]
 pub struct TextFilter<'a>(pub &'a [&'a str], pub TextMatchMethod);
 
+/// Filters using provided regex.
+#[derive(Clone)]
+pub struct RegexFilter(pub Regex);
+
 impl Filter for ExcludedChatsFilter {
     fn filter(&self, update: &Update) -> anyhow::Result<bool> {
         let a = match update {
@@ -89,3 +95,10 @@ impl Filter for SilentFilter {
         Ok(!message.silent())
     }
 }
+
+impl Filter for RegexFilter {
+    fn filter(&self, update: &Update) -> anyhow::Result<bool> {
+        let Some(message) = get_message(update) else {return Ok(false)};
+        Ok(self.0.is_match(message.text()))
+    }
+}
diff --git a/src/bot/handlers/basic/mod.rs b/src/bot/handlers/basic/mod.rs
index 3f81a214a474dcf573fca1e475444a68aa3e2012..acc4306c2c07cd0186f2ccdb38ce2a1b09f9ecde 100644
--- a/src/bot/handlers/basic/mod.rs
+++ b/src/bot/handlers/basic/mod.rs
@@ -1,3 +1,4 @@
 pub mod currency_converter;
 pub mod get_chat_id;
 pub mod help;
+pub mod weather_forecaster;
diff --git a/src/bot/handlers/basic/weather_forecaster.rs b/src/bot/handlers/basic/weather_forecaster.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2edd4a76574b534677b0c90d84225db9d013eb7a
--- /dev/null
+++ b/src/bot/handlers/basic/weather_forecaster.rs
@@ -0,0 +1,84 @@
+use std::time::Duration;
+
+use grammers_client::{Client, InputMessage, Update};
+use rand::seq::SliceRandom;
+
+use crate::{bot::handlers::Handler, utils::messages::get_message};
+use rand::rngs::OsRng;
+
+#[derive(Clone)]
+pub struct WeatherForecaster {
+    client: reqwest::Client,
+}
+
+impl WeatherForecaster {
+    pub fn new() -> anyhow::Result<Self> {
+        let client = reqwest::ClientBuilder::new()
+            .timeout(Duration::from_secs(2))
+            .gzip(true)
+            .build()?;
+        Ok(Self { client })
+    }
+}
+
+#[async_trait::async_trait]
+impl Handler for WeatherForecaster {
+    async fn react(&self, _: &Client, update: &Update) -> anyhow::Result<()> {
+        let Some(message) = get_message(update) else {
+            return Ok(());
+        };
+        let Some(city) = message.text().strip_prefix(".w").map(str::trim) else {
+            return Ok(());
+        };
+
+        let response = self
+            .client
+            .get(format!("https://wttr.in/{city}?0QT"))
+            .header("user-agent", "curl/7.0")
+            .send()
+            .await?;
+
+        if response.status() == reqwest::StatusCode::NOT_FOUND {
+            message
+                .reply(
+                    [
+                        "Лол, ты сам-то понял что написал?",
+                        "Не, я хз где это.",
+                        "Если ты действительно тут живешь, то сочувствую.",
+                    ]
+                    .choose(&mut OsRng)
+                    .copied()
+                    .unwrap(),
+                )
+                .await?;
+            return Ok(());
+        }
+
+        if response.status() != reqwest::StatusCode::OK {
+            message.reply("Сервис недоступен. Попробуй потом.").await?;
+            return Ok(());
+        }
+
+        let forecast = response.text().await?;
+
+        message
+            .reply(
+                InputMessage::html(
+                    forecast
+                        // We need to wrap every line in pre tag.
+                        .split('\n')
+                        .filter(|line| !line.trim().is_empty())
+                        .map(|line| format!("<pre>{line}</pre>\n"))
+                        // Also we add a message at the end by chaining another
+                        // iterable.
+                        .chain([String::from("Ваш прогноз.")])
+                        // And collect interator to final HTML string.
+                        .collect::<String>(),
+                )
+                .silent(true),
+            )
+            .await?;
+
+        Ok(())
+    }
+}
diff --git a/src/bot/handlers/fun/mod.rs b/src/bot/handlers/fun/mod.rs
index 8d24276ed9b86f90ce272366a8ef75505d39950c..46355f68b71815a1ff211e692068119d1a7840a0 100644
--- a/src/bot/handlers/fun/mod.rs
+++ b/src/bot/handlers/fun/mod.rs
@@ -1,3 +1,4 @@
 pub mod blyaficator;
 pub mod greeter;
+pub mod repeator;
 pub mod rotator;
diff --git a/src/bot/handlers/fun/repeator.rs b/src/bot/handlers/fun/repeator.rs
new file mode 100644
index 0000000000000000000000000000000000000000..20398e3c548319a8982379a79775c2b75d0633c3
--- /dev/null
+++ b/src/bot/handlers/fun/repeator.rs
@@ -0,0 +1,15 @@
+use grammers_client::{Client, Update};
+
+use crate::{bot::handlers::Handler, utils::messages::get_message};
+
+#[derive(Clone)]
+pub struct Repeator;
+
+#[async_trait::async_trait]
+impl Handler for Repeator {
+    async fn react(&self, _: &Client, update: &Update) -> anyhow::Result<()> {
+        let Some(message) = get_message(update) else { return Ok(()) };
+        message.respond(message.text()).await?;
+        Ok(())
+    }
+}
diff --git a/src/bot/main.rs b/src/bot/main.rs
index 1288014fc6acbb285a0f58602788cf3214a80ad2..5ddd3823f7938dc9c20b21fc07bfe111af3fba7f 100644
--- a/src/bot/main.rs
+++ b/src/bot/main.rs
@@ -4,14 +4,15 @@ use crate::args::BotConfig;
 use grammers_client::{Client, Config, SignInError, Update};
 use grammers_session::Session;
 use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
+use regex::Regex;
 use tokio::sync::RwLock;
 
 use super::{
     filters::{
         filtered_handler::FilteredHandler,
         message_fitlers::{
-            ExcludedChatsFilter, MessageDirection, MessageDirectionFilter, SilentFilter,
-            TextFilter, TextMatchMethod,
+            ExcludedChatsFilter, MessageDirection, MessageDirectionFilter, RegexFilter,
+            SilentFilter, TextFilter, TextMatchMethod,
         },
     },
     handlers::{
@@ -19,8 +20,9 @@ use super::{
             currency_converter::{CurrencyConverter, CurrencyTextFilter},
             get_chat_id::GetChatId,
             help::Help,
+            weather_forecaster::WeatherForecaster,
         },
-        fun::{blyaficator::Blyaficator, greeter::Greeter, rotator::Rotator},
+        fun::{blyaficator::Blyaficator, greeter::Greeter, repeator::Repeator, rotator::Rotator},
         Handler,
     },
 };
@@ -90,11 +92,13 @@ async fn handle_with_log(handler: Box<dyn Handler>, client: Client, update_data:
 ///
 /// Also, every available handler is defined here.
 async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> {
+    let me = client.get_me().await?;
     let handlers: Vec<FilteredHandler> = vec![
         // Printing help.
         FilteredHandler::new(Help).add_filter(TextFilter(&[".h"], TextMatchMethod::IMatches)),
         // Greeting my fellow humans.
         FilteredHandler::new(Greeter)
+            .add_filter(ExcludedChatsFilter(vec![me.id()]))
             .add_filter(SilentFilter)
             .add_filter(MessageDirectionFilter(MessageDirection::Incoming))
             .add_filter(TextFilter(&["привет"], TextMatchMethod::IStartsWith))
@@ -115,6 +119,16 @@ async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> {
         FilteredHandler::new(Rotator)
             .add_filter(SilentFilter)
             .add_filter(TextFilter(&[".rl"], TextMatchMethod::IStartsWith)),
+        // Weather forecast.
+        FilteredHandler::new(WeatherForecaster::new()?)
+            .add_filter(SilentFilter)
+            .add_filter(TextFilter(&[".w"], TextMatchMethod::IStartsWith)),
+        // Smiley repeator.
+        FilteredHandler::new(Repeator)
+            .add_filter(ExcludedChatsFilter(vec![me.id()]))
+            .add_filter(MessageDirectionFilter(MessageDirection::Incoming))
+            .add_filter(SilentFilter)
+            .add_filter(RegexFilter(Regex::new("^[)0]+$")?)),
     ];
 
     let mut errors_count = 0;
@@ -154,7 +168,6 @@ async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> {
     }
     Ok(())
 }
-
 pub async fn bot_life(
     args: BotConfig,
     web_code: Arc<RwLock<Option<String>>>,