mirror of
https://github.com/Misterio77/Foundry.git
synced 2026-08-24 02:14:13 -05:00
1073 lines
31 KiB
Diff
1073 lines
31 KiB
Diff
From bec307c314a2e81ab14e2156a6e2b7e9364f7780 Mon Sep 17 00:00:00 2001
|
|
From: Gabriel Fontes <hi@m7.rs>
|
|
Date: Mon, 9 Mar 2026 23:29:26 -0300
|
|
Subject: [PATCH 1/4] refactor: switch to async
|
|
|
|
Co-Authored-By: ilkecan <ilkecan@protonmail.com>
|
|
---
|
|
Cargo.lock | 217 ++++++++++++++--------------------------------------
|
|
Cargo.toml | 13 +++-
|
|
src/main.rs | 38 +++++----
|
|
3 files changed, 90 insertions(+), 178 deletions(-)
|
|
|
|
diff --git a/Cargo.lock b/Cargo.lock
|
|
index e9835a6..8b56695 100644
|
|
--- a/Cargo.lock
|
|
+++ b/Cargo.lock
|
|
@@ -79,79 +79,6 @@ dependencies = [
|
|
"pin-project-lite",
|
|
]
|
|
|
|
-[[package]]
|
|
-name = "async-channel"
|
|
-version = "2.5.0"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
|
|
-dependencies = [
|
|
- "concurrent-queue",
|
|
- "event-listener-strategy",
|
|
- "futures-core",
|
|
- "pin-project-lite",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
-name = "async-executor"
|
|
-version = "1.14.0"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
|
|
-dependencies = [
|
|
- "async-task",
|
|
- "concurrent-queue",
|
|
- "fastrand",
|
|
- "futures-lite",
|
|
- "pin-project-lite",
|
|
- "slab",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
-name = "async-io"
|
|
-version = "2.6.0"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
|
-dependencies = [
|
|
- "autocfg",
|
|
- "cfg-if",
|
|
- "concurrent-queue",
|
|
- "futures-io",
|
|
- "futures-lite",
|
|
- "parking",
|
|
- "polling",
|
|
- "rustix",
|
|
- "slab",
|
|
- "windows-sys",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
-name = "async-lock"
|
|
-version = "3.4.2"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
|
-dependencies = [
|
|
- "event-listener",
|
|
- "event-listener-strategy",
|
|
- "pin-project-lite",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
-name = "async-process"
|
|
-version = "2.5.0"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
|
-dependencies = [
|
|
- "async-channel",
|
|
- "async-io",
|
|
- "async-lock",
|
|
- "async-signal",
|
|
- "async-task",
|
|
- "blocking",
|
|
- "cfg-if",
|
|
- "event-listener",
|
|
- "futures-lite",
|
|
- "rustix",
|
|
-]
|
|
-
|
|
[[package]]
|
|
name = "async-recursion"
|
|
version = "1.1.1"
|
|
@@ -163,30 +90,6 @@ dependencies = [
|
|
"syn",
|
|
]
|
|
|
|
-[[package]]
|
|
-name = "async-signal"
|
|
-version = "0.2.13"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c"
|
|
-dependencies = [
|
|
- "async-io",
|
|
- "async-lock",
|
|
- "atomic-waker",
|
|
- "cfg-if",
|
|
- "futures-core",
|
|
- "futures-io",
|
|
- "rustix",
|
|
- "signal-hook-registry",
|
|
- "slab",
|
|
- "windows-sys",
|
|
-]
|
|
-
|
|
-[[package]]
|
|
-name = "async-task"
|
|
-version = "4.7.1"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
|
-
|
|
[[package]]
|
|
name = "async-trait"
|
|
version = "0.1.89"
|
|
@@ -198,12 +101,6 @@ dependencies = [
|
|
"syn",
|
|
]
|
|
|
|
-[[package]]
|
|
-name = "atomic-waker"
|
|
-version = "1.1.2"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
|
-
|
|
[[package]]
|
|
name = "autocfg"
|
|
version = "1.5.0"
|
|
@@ -216,7 +113,9 @@ version = "2.0.127"
|
|
dependencies = [
|
|
"clap",
|
|
"env_logger",
|
|
+ "futures-lite",
|
|
"log",
|
|
+ "tokio",
|
|
"trycmd",
|
|
"tzf-rs",
|
|
"zbus",
|
|
@@ -240,19 +139,6 @@ version = "2.11.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
|
|
|
-[[package]]
|
|
-name = "blocking"
|
|
-version = "1.6.2"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
|
|
-dependencies = [
|
|
- "async-channel",
|
|
- "async-task",
|
|
- "futures-io",
|
|
- "futures-lite",
|
|
- "piper",
|
|
-]
|
|
-
|
|
[[package]]
|
|
name = "bumpalo"
|
|
version = "3.20.2"
|
|
@@ -556,12 +442,6 @@ version = "0.5.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
|
|
-[[package]]
|
|
-name = "hermit-abi"
|
|
-version = "0.5.2"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
|
-
|
|
[[package]]
|
|
name = "hex"
|
|
version = "0.4.3"
|
|
@@ -684,6 +564,17 @@ dependencies = [
|
|
"autocfg",
|
|
]
|
|
|
|
+[[package]]
|
|
+name = "mio"
|
|
+version = "1.2.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
|
+dependencies = [
|
|
+ "libc",
|
|
+ "wasi",
|
|
+ "windows-sys",
|
|
+]
|
|
+
|
|
[[package]]
|
|
name = "multimap"
|
|
version = "0.10.1"
|
|
@@ -751,37 +642,12 @@ version = "0.2.17"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
|
|
|
-[[package]]
|
|
-name = "piper"
|
|
-version = "0.2.5"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
|
-dependencies = [
|
|
- "atomic-waker",
|
|
- "fastrand",
|
|
- "futures-io",
|
|
-]
|
|
-
|
|
[[package]]
|
|
name = "plain"
|
|
version = "0.2.3"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
|
|
|
-[[package]]
|
|
-name = "polling"
|
|
-version = "3.11.0"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
|
|
-dependencies = [
|
|
- "cfg-if",
|
|
- "concurrent-queue",
|
|
- "hermit-abi",
|
|
- "pin-project-lite",
|
|
- "rustix",
|
|
- "windows-sys",
|
|
-]
|
|
-
|
|
[[package]]
|
|
name = "pqueue"
|
|
version = "0.1.0"
|
|
@@ -1068,12 +934,6 @@ version = "2.7.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
|
|
|
-[[package]]
|
|
-name = "slab"
|
|
-version = "0.4.12"
|
|
-source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
|
-
|
|
[[package]]
|
|
name = "snapbox"
|
|
version = "1.2.0"
|
|
@@ -1105,6 +965,16 @@ dependencies = [
|
|
"anstream",
|
|
]
|
|
|
|
+[[package]]
|
|
+name = "socket2"
|
|
+version = "0.6.3"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
|
+dependencies = [
|
|
+ "libc",
|
|
+ "windows-sys",
|
|
+]
|
|
+
|
|
[[package]]
|
|
name = "syn"
|
|
version = "2.0.117"
|
|
@@ -1129,6 +999,34 @@ dependencies = [
|
|
"windows-sys",
|
|
]
|
|
|
|
+[[package]]
|
|
+name = "tokio"
|
|
+version = "1.50.0"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
|
|
+dependencies = [
|
|
+ "bytes",
|
|
+ "libc",
|
|
+ "mio",
|
|
+ "pin-project-lite",
|
|
+ "signal-hook-registry",
|
|
+ "socket2",
|
|
+ "tokio-macros",
|
|
+ "tracing",
|
|
+ "windows-sys",
|
|
+]
|
|
+
|
|
+[[package]]
|
|
+name = "tokio-macros"
|
|
+version = "2.6.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c"
|
|
+dependencies = [
|
|
+ "proc-macro2",
|
|
+ "quote",
|
|
+ "syn",
|
|
+]
|
|
+
|
|
[[package]]
|
|
name = "toml_datetime"
|
|
version = "1.1.1+spec-1.1.0"
|
|
@@ -1296,6 +1194,12 @@ dependencies = [
|
|
"winapi-util",
|
|
]
|
|
|
|
+[[package]]
|
|
+name = "wasi"
|
|
+version = "0.11.1+wasi-snapshot-preview1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
+
|
|
[[package]]
|
|
name = "wasip2"
|
|
version = "1.0.2+wasi-0.2.9"
|
|
@@ -1530,14 +1434,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc"
|
|
dependencies = [
|
|
"async-broadcast",
|
|
- "async-executor",
|
|
- "async-io",
|
|
- "async-lock",
|
|
- "async-process",
|
|
"async-recursion",
|
|
- "async-task",
|
|
"async-trait",
|
|
- "blocking",
|
|
"enumflags2",
|
|
"event-listener",
|
|
"futures-core",
|
|
@@ -1548,6 +1446,7 @@ dependencies = [
|
|
"rustix",
|
|
"serde",
|
|
"serde_repr",
|
|
+ "tokio",
|
|
"tracing",
|
|
"uds_windows",
|
|
"uuid",
|
|
diff --git a/Cargo.toml b/Cargo.toml
|
|
index 715fb54..c198f43 100644
|
|
--- a/Cargo.toml
|
|
+++ b/Cargo.toml
|
|
@@ -12,6 +12,16 @@ env_logger = { version = "=0.11.10", default-features = false }
|
|
log = { version = "=0.4.29", default-features = false }
|
|
tzf-rs = { version = "=1.2.0", default-features = false }
|
|
zvariant = { version = "=5.10.0", default-features = false }
|
|
+futures-lite = { version = "=2.6.1", default-features = false }
|
|
+
|
|
+[dependencies.tokio]
|
|
+version = "=1.50.0"
|
|
+default-features = false
|
|
+features = [
|
|
+ "macros",
|
|
+ "rt",
|
|
+ "time"
|
|
+]
|
|
|
|
[dependencies.clap]
|
|
version = "=4.6.1"
|
|
@@ -29,8 +39,7 @@ features = [
|
|
version = "=5.14.0"
|
|
default-features = false
|
|
features = [
|
|
- "async-io",
|
|
- "blocking-api",
|
|
+ "tokio"
|
|
]
|
|
|
|
[dev-dependencies]
|
|
diff --git a/src/main.rs b/src/main.rs
|
|
index f6342c1..6ee35a5 100644
|
|
--- a/src/main.rs
|
|
+++ b/src/main.rs
|
|
@@ -3,9 +3,10 @@
|
|
use std::error::Error;
|
|
|
|
use clap::Parser;
|
|
+use futures_lite::stream::StreamExt;
|
|
use log::{debug, error, info};
|
|
use tzf_rs::DefaultFinder;
|
|
-use zbus::{blocking::Connection, proxy};
|
|
+use zbus::{proxy, Connection};
|
|
|
|
mod geoclue;
|
|
|
|
@@ -28,7 +29,8 @@ trait Timedate {
|
|
fn set_timezone(&self, timezone: &str, interactive: bool) -> zbus::Result<()>;
|
|
}
|
|
|
|
-fn main() -> Result<(), Box<dyn Error>> {
|
|
+#[tokio::main(flavor = "current_thread")]
|
|
+async fn main() -> Result<(), Box<dyn Error>> {
|
|
let args = Args::parse();
|
|
|
|
env_logger::Builder::new()
|
|
@@ -43,29 +45,31 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
let zone_finder = DefaultFinder::new();
|
|
|
|
- let conn = Connection::system()?;
|
|
+ let conn = Connection::system().await?;
|
|
|
|
- let gclue_manager = geoclue::ManagerProxyBlocking::new(&conn)?;
|
|
- let gclue_client = gclue_manager.get_client()?;
|
|
- gclue_client.set_desktop_id("automatic-timezoned")?;
|
|
- gclue_client.set_distance_threshold(10000)?; // meters
|
|
- gclue_client.set_requested_accuracy_level(geoclue::AccuracyLevel::City as u32)?;
|
|
+ let gclue_manager = geoclue::ManagerProxy::new(&conn).await?;
|
|
+ let gclue_client = gclue_manager.get_client().await?;
|
|
+ gclue_client.set_desktop_id("automatic-timezoned").await?;
|
|
+ gclue_client.set_distance_threshold(10000).await?; // meters
|
|
+ gclue_client
|
|
+ .set_requested_accuracy_level(geoclue::AccuracyLevel::City as u32)
|
|
+ .await?;
|
|
|
|
- let timedate = TimedateProxyBlocking::new(&conn)?;
|
|
+ let timedate = TimedateProxy::new(&conn).await?;
|
|
|
|
- let location_updated = gclue_client.receive_location_updated()?;
|
|
+ let mut location_updated = gclue_client.receive_location_updated().await?;
|
|
|
|
- gclue_client.start()?;
|
|
+ gclue_client.start().await?;
|
|
|
|
- for signal in location_updated {
|
|
+ while let Some(signal) = location_updated.next().await {
|
|
let args = signal.args()?;
|
|
|
|
- let location = geoclue::LocationProxyBlocking::builder(&conn)
|
|
+ let location = geoclue::LocationProxy::builder(&conn)
|
|
.path(args.new())?
|
|
- .build()?;
|
|
+ .build().await?;
|
|
|
|
- let latitude = location.latitude()?;
|
|
- let longitude = location.longitude()?;
|
|
+ let latitude = location.latitude().await?;
|
|
+ let longitude = location.longitude().await?;
|
|
|
|
debug!("Received location update. Latitude: {latitude} / Longitude: {longitude}");
|
|
|
|
@@ -76,7 +80,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|
continue;
|
|
}
|
|
|
|
- timedate.set_timezone(timezone, false)?;
|
|
+ timedate.set_timezone(timezone, false).await?;
|
|
info!("Set timezone to \"{timezone}\"",);
|
|
}
|
|
|
|
--
|
|
2.52.0
|
|
|
|
|
|
From af1dfe237b0540d4bbee37f9d85be7f010553598 Mon Sep 17 00:00:00 2001
|
|
From: Gabriel Fontes <hi@m7.rs>
|
|
Date: Mon, 9 Mar 2026 23:37:27 -0300
|
|
Subject: [PATCH 2/4] refactor: extract location handling to function
|
|
|
|
---
|
|
src/main.rs | 51 +++++++++++++++++++++++++++++++--------------------
|
|
1 file changed, 31 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/src/main.rs b/src/main.rs
|
|
index 6ee35a5..2594d1f 100644
|
|
--- a/src/main.rs
|
|
+++ b/src/main.rs
|
|
@@ -29,6 +29,36 @@ trait Timedate {
|
|
fn set_timezone(&self, timezone: &str, interactive: bool) -> zbus::Result<()>;
|
|
}
|
|
|
|
+async fn handle_location(
|
|
+ signal: geoclue::LocationUpdated,
|
|
+ timedate: &TimedateProxy<'_>,
|
|
+ zone_finder: &DefaultFinder,
|
|
+ conn: &Connection,
|
|
+) -> Result<(), Box<dyn Error>> {
|
|
+ let args = signal.args()?;
|
|
+
|
|
+ let location = geoclue::LocationProxy::builder(&conn)
|
|
+ .path(args.new())?
|
|
+ .build()
|
|
+ .await?;
|
|
+
|
|
+ let latitude = location.latitude().await?;
|
|
+ let longitude = location.longitude().await?;
|
|
+
|
|
+ debug!("Received location update. Latitude: {latitude} / Longitude: {longitude}");
|
|
+
|
|
+ let timezone = zone_finder.get_tz_name(longitude, latitude);
|
|
+
|
|
+ if timezone.is_empty() {
|
|
+ error!("Failed to find a timezone. Latitude: {latitude} / Longitude: {longitude}");
|
|
+ } else {
|
|
+ timedate.set_timezone(timezone, false).await?;
|
|
+ info!("Set timezone to \"{timezone}\"",);
|
|
+ }
|
|
+
|
|
+ Ok(())
|
|
+}
|
|
+
|
|
#[tokio::main(flavor = "current_thread")]
|
|
async fn main() -> Result<(), Box<dyn Error>> {
|
|
let args = Args::parse();
|
|
@@ -62,26 +92,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|
gclue_client.start().await?;
|
|
|
|
while let Some(signal) = location_updated.next().await {
|
|
- let args = signal.args()?;
|
|
-
|
|
- let location = geoclue::LocationProxy::builder(&conn)
|
|
- .path(args.new())?
|
|
- .build().await?;
|
|
-
|
|
- let latitude = location.latitude().await?;
|
|
- let longitude = location.longitude().await?;
|
|
-
|
|
- debug!("Received location update. Latitude: {latitude} / Longitude: {longitude}");
|
|
-
|
|
- let timezone = zone_finder.get_tz_name(longitude, latitude);
|
|
-
|
|
- if timezone.is_empty() {
|
|
- error!("Failed to find a timezone. Latitude: {latitude} / Longitude: {longitude}");
|
|
- continue;
|
|
- }
|
|
-
|
|
- timedate.set_timezone(timezone, false).await?;
|
|
- info!("Set timezone to \"{timezone}\"",);
|
|
+ handle_location(signal, &timedate, &zone_finder, &conn).await?
|
|
}
|
|
|
|
Ok(())
|
|
--
|
|
2.52.0
|
|
|
|
|
|
From 0c9377bfcc96488d95468d8a8656dfbd1c41526b Mon Sep 17 00:00:00 2001
|
|
From: Gabriel Fontes <hi@m7.rs>
|
|
Date: Mon, 9 Mar 2026 23:45:56 -0300
|
|
Subject: [PATCH 3/4] refactor: use anyhow for error handling
|
|
|
|
---
|
|
Cargo.lock | 135 ++++++++++++++++++++++++++++++++--------------------
|
|
Cargo.toml | 1 +
|
|
src/main.rs | 6 +--
|
|
3 files changed, 88 insertions(+), 54 deletions(-)
|
|
|
|
diff --git a/Cargo.lock b/Cargo.lock
|
|
index 8b56695..b037a41 100644
|
|
--- a/Cargo.lock
|
|
+++ b/Cargo.lock
|
|
@@ -111,6 +111,7 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
name = "automatic-timezoned"
|
|
version = "2.0.127"
|
|
dependencies = [
|
|
+ "anyhow",
|
|
"clap",
|
|
"env_logger",
|
|
"futures-lite",
|
|
@@ -135,9 +136,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "bitflags"
|
|
-version = "2.11.0"
|
|
+version = "2.11.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
|
+checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
|
|
|
[[package]]
|
|
name = "bumpalo"
|
|
@@ -341,9 +342,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "fastrand"
|
|
-version = "2.3.0"
|
|
+version = "2.4.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
|
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
|
|
|
[[package]]
|
|
name = "filetime"
|
|
@@ -393,6 +394,24 @@ dependencies = [
|
|
"pin-project-lite",
|
|
]
|
|
|
|
+[[package]]
|
|
+name = "futures-task"
|
|
+version = "0.3.32"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
|
+
|
|
+[[package]]
|
|
+name = "futures-util"
|
|
+version = "0.3.32"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
|
+dependencies = [
|
|
+ "futures-core",
|
|
+ "futures-task",
|
|
+ "pin-project-lite",
|
|
+ "slab",
|
|
+]
|
|
+
|
|
[[package]]
|
|
name = "geometry-rs"
|
|
version = "0.4.1"
|
|
@@ -432,9 +451,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "hashbrown"
|
|
-version = "0.16.1"
|
|
+version = "0.17.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
|
+checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
|
|
|
|
[[package]]
|
|
name = "heck"
|
|
@@ -472,12 +491,12 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
|
|
|
[[package]]
|
|
name = "indexmap"
|
|
-version = "2.13.0"
|
|
+version = "2.14.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
|
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
|
dependencies = [
|
|
"equivalent",
|
|
- "hashbrown 0.16.1",
|
|
+ "hashbrown 0.17.0",
|
|
"serde",
|
|
"serde_core",
|
|
]
|
|
@@ -505,10 +524,12 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
|
|
[[package]]
|
|
name = "js-sys"
|
|
-version = "0.3.94"
|
|
+version = "0.3.97"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9"
|
|
+checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
|
|
dependencies = [
|
|
+ "cfg-if",
|
|
+ "futures-util",
|
|
"once_cell",
|
|
"wasm-bindgen",
|
|
]
|
|
@@ -521,15 +542,15 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|
|
|
[[package]]
|
|
name = "libc"
|
|
-version = "0.2.183"
|
|
+version = "0.2.186"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
|
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
|
|
[[package]]
|
|
name = "libredox"
|
|
-version = "0.1.15"
|
|
+version = "0.1.16"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08"
|
|
+checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
|
|
dependencies = [
|
|
"bitflags",
|
|
"libc",
|
|
@@ -750,9 +771,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
|
|
|
[[package]]
|
|
name = "rayon"
|
|
-version = "1.11.0"
|
|
+version = "1.12.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
|
+checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
|
dependencies = [
|
|
"either",
|
|
"rayon-core",
|
|
@@ -770,9 +791,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "redox_syscall"
|
|
-version = "0.7.3"
|
|
+version = "0.7.4"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16"
|
|
+checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a"
|
|
dependencies = [
|
|
"bitflags",
|
|
]
|
|
@@ -845,9 +866,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "semver"
|
|
-version = "1.0.27"
|
|
+version = "1.0.28"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
|
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
|
|
|
[[package]]
|
|
name = "serde"
|
|
@@ -935,10 +956,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
|
|
|
[[package]]
|
|
-name = "snapbox"
|
|
-version = "1.2.0"
|
|
+name = "slab"
|
|
+version = "0.4.12"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "8d9a4b69d5b4116a26b662c0bb38895261da3f3bfc171657d66a2a3c7a41e929"
|
|
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
|
+
|
|
+[[package]]
|
|
+name = "snapbox"
|
|
+version = "1.2.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "f92ac911648d788a6435401d9b4803959039d4de9919fdabdb415a8bebd027be"
|
|
dependencies = [
|
|
"anstream",
|
|
"anstyle",
|
|
@@ -1038,9 +1065,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "toml_edit"
|
|
-version = "0.25.9+spec-1.1.0"
|
|
+version = "0.25.11+spec-1.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "da053d28fe57e2c9d21b48261e14e7b4c8b670b54d2c684847b91feaf4c7dac5"
|
|
+checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
|
dependencies = [
|
|
"indexmap",
|
|
"serde_core",
|
|
@@ -1048,16 +1075,16 @@ dependencies = [
|
|
"toml_datetime",
|
|
"toml_parser",
|
|
"toml_writer",
|
|
- "winnow 1.0.1",
|
|
+ "winnow 1.0.2",
|
|
]
|
|
|
|
[[package]]
|
|
name = "toml_parser"
|
|
-version = "1.1.1+spec-1.1.0"
|
|
+version = "1.1.2+spec-1.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "39ca317ebc49f06bd748bfba29533eac9485569dc9bf80b849024b025e814fb9"
|
|
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
|
dependencies = [
|
|
- "winnow 1.0.1",
|
|
+ "winnow 1.0.2",
|
|
]
|
|
|
|
[[package]]
|
|
@@ -1166,9 +1193,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|
|
|
[[package]]
|
|
name = "uuid"
|
|
-version = "1.23.0"
|
|
+version = "1.23.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
|
|
+checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
|
|
dependencies = [
|
|
"js-sys",
|
|
"serde_core",
|
|
@@ -1202,11 +1229,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
|
|
[[package]]
|
|
name = "wasip2"
|
|
-version = "1.0.2+wasi-0.2.9"
|
|
+version = "1.0.3+wasi-0.2.9"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
|
+checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
|
dependencies = [
|
|
- "wit-bindgen",
|
|
+ "wit-bindgen 0.57.1",
|
|
]
|
|
|
|
[[package]]
|
|
@@ -1215,14 +1242,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
|
dependencies = [
|
|
- "wit-bindgen",
|
|
+ "wit-bindgen 0.51.0",
|
|
]
|
|
|
|
[[package]]
|
|
name = "wasm-bindgen"
|
|
-version = "0.2.117"
|
|
+version = "0.2.120"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0"
|
|
+checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
|
|
dependencies = [
|
|
"cfg-if",
|
|
"once_cell",
|
|
@@ -1233,9 +1260,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "wasm-bindgen-macro"
|
|
-version = "0.2.117"
|
|
+version = "0.2.120"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be"
|
|
+checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
|
|
dependencies = [
|
|
"quote",
|
|
"wasm-bindgen-macro-support",
|
|
@@ -1243,9 +1270,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "wasm-bindgen-macro-support"
|
|
-version = "0.2.117"
|
|
+version = "0.2.120"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2"
|
|
+checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
|
|
dependencies = [
|
|
"bumpalo",
|
|
"proc-macro2",
|
|
@@ -1256,9 +1283,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "wasm-bindgen-shared"
|
|
-version = "0.2.117"
|
|
+version = "0.2.120"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b"
|
|
+checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
|
|
dependencies = [
|
|
"unicode-ident",
|
|
]
|
|
@@ -1332,9 +1359,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "winnow"
|
|
-version = "1.0.1"
|
|
+version = "1.0.2"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
|
|
+checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
|
|
dependencies = [
|
|
"memchr",
|
|
]
|
|
@@ -1348,6 +1375,12 @@ dependencies = [
|
|
"wit-bindgen-rust-macro",
|
|
]
|
|
|
|
+[[package]]
|
|
+name = "wit-bindgen"
|
|
+version = "0.57.1"
|
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
+
|
|
[[package]]
|
|
name = "wit-bindgen-core"
|
|
version = "0.51.0"
|
|
@@ -1505,9 +1538,9 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "zvariant_derive"
|
|
-version = "5.10.0"
|
|
+version = "5.10.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c"
|
|
+checksum = "5b949b639ab1b4bed763aa7481ba0e368af68d8b55532f8ed4bec86a59f2ca98"
|
|
dependencies = [
|
|
"proc-macro-crate",
|
|
"proc-macro2",
|
|
@@ -1518,13 +1551,13 @@ dependencies = [
|
|
|
|
[[package]]
|
|
name = "zvariant_utils"
|
|
-version = "3.3.0"
|
|
+version = "3.3.1"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
-checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9"
|
|
+checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691"
|
|
dependencies = [
|
|
"proc-macro2",
|
|
"quote",
|
|
"serde",
|
|
"syn",
|
|
- "winnow 0.7.15",
|
|
+ "winnow 1.0.2",
|
|
]
|
|
diff --git a/Cargo.toml b/Cargo.toml
|
|
index c198f43..5af7411 100644
|
|
--- a/Cargo.toml
|
|
+++ b/Cargo.toml
|
|
@@ -8,6 +8,7 @@ license = "GPL-3.0"
|
|
keywords = ["dbus", "geoclue", "systemd", "timezone", "zoneinfo"]
|
|
|
|
[dependencies]
|
|
+anyhow = { version = "=1.0.102", default-features = false }
|
|
env_logger = { version = "=0.11.10", default-features = false }
|
|
log = { version = "=0.4.29", default-features = false }
|
|
tzf-rs = { version = "=1.2.0", default-features = false }
|
|
diff --git a/src/main.rs b/src/main.rs
|
|
index 2594d1f..428f7f8 100644
|
|
--- a/src/main.rs
|
|
+++ b/src/main.rs
|
|
@@ -1,7 +1,7 @@
|
|
#![warn(clippy::all)]
|
|
|
|
-use std::error::Error;
|
|
|
|
+use anyhow::Result;
|
|
use clap::Parser;
|
|
use futures_lite::stream::StreamExt;
|
|
use log::{debug, error, info};
|
|
@@ -34,7 +34,7 @@ async fn handle_location(
|
|
timedate: &TimedateProxy<'_>,
|
|
zone_finder: &DefaultFinder,
|
|
conn: &Connection,
|
|
-) -> Result<(), Box<dyn Error>> {
|
|
+) -> Result<()> {
|
|
let args = signal.args()?;
|
|
|
|
let location = geoclue::LocationProxy::builder(&conn)
|
|
@@ -60,7 +60,7 @@ async fn handle_location(
|
|
}
|
|
|
|
#[tokio::main(flavor = "current_thread")]
|
|
-async fn main() -> Result<(), Box<dyn Error>> {
|
|
+async fn main() -> Result<()> {
|
|
let args = Args::parse();
|
|
|
|
env_logger::Builder::new()
|
|
--
|
|
2.52.0
|
|
|
|
|
|
From 88de21b14c6995f1fd1992876382151aa6e73aa4 Mon Sep 17 00:00:00 2001
|
|
From: Gabriel Fontes <hi@m7.rs>
|
|
Date: Mon, 9 Mar 2026 23:45:56 -0300
|
|
Subject: [PATCH 4/4] feature: add timeout for geoclue connection and first
|
|
location update
|
|
|
|
---
|
|
README.md | 7 ++++---
|
|
src/main.rs | 22 ++++++++++++++++++++--
|
|
tests/cmd/help.md | 14 ++++++++------
|
|
3 files changed, 32 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/README.md b/README.md
|
|
index 11ce166..d8dc0fc 100644
|
|
--- a/README.md
|
|
+++ b/README.md
|
|
@@ -34,9 +34,10 @@ Automatically update system timezone based on location
|
|
Usage: automatic-timezoned [OPTIONS]
|
|
|
|
Options:
|
|
- -l, --log-level <LOG_LEVEL> Log level filter. See <https://docs.rs/env_logger> for syntax [env: AUTOTZD_LOG_LEVEL=] [default: info]
|
|
- -h, --help Print help
|
|
- -V, --version Print version
|
|
+ -l, --log-level <LOG_LEVEL> Log level filter. See <https://docs.rs/env_logger> for syntax [env: AUTOTZD_LOG_LEVEL=] [default: info]
|
|
+ -t, --timeout-secs <TIMEOUT_SECS> Timeout in seconds for connections [env: AUTOTZD_TIMEOUT_SECS=] [default: 30]
|
|
+ -h, --help Print help
|
|
+ -V, --version Print version
|
|
|
|
```
|
|
|
|
diff --git a/src/main.rs b/src/main.rs
|
|
index 428f7f8..cd38063 100644
|
|
--- a/src/main.rs
|
|
+++ b/src/main.rs
|
|
@@ -1,10 +1,12 @@
|
|
#![warn(clippy::all)]
|
|
|
|
+use std::time::Duration;
|
|
|
|
-use anyhow::Result;
|
|
+use anyhow::{Context, Result};
|
|
use clap::Parser;
|
|
use futures_lite::stream::StreamExt;
|
|
use log::{debug, error, info};
|
|
+use tokio::time::timeout;
|
|
use tzf_rs::DefaultFinder;
|
|
use zbus::{proxy, Connection};
|
|
|
|
@@ -17,6 +19,9 @@ struct Args {
|
|
/// Log level filter. See <https://docs.rs/env_logger> for syntax
|
|
#[arg(short, long, default_value = "info", env = "AUTOTZD_LOG_LEVEL")]
|
|
log_level: String,
|
|
+ /// Timeout in seconds for connections.
|
|
+ #[arg(short, long, default_value = "30", env = "AUTOTZD_TIMEOUT_SECS")]
|
|
+ timeout_secs: u16,
|
|
}
|
|
|
|
#[proxy(
|
|
@@ -67,6 +72,8 @@ async fn main() -> Result<()> {
|
|
.parse_filters(&args.log_level)
|
|
.init();
|
|
|
|
+ let timeout_s = Duration::from_secs(args.timeout_secs.into());
|
|
+
|
|
info!(
|
|
"Starting {} {}...",
|
|
env!("CARGO_PKG_NAME"),
|
|
@@ -78,7 +85,9 @@ async fn main() -> Result<()> {
|
|
let conn = Connection::system().await?;
|
|
|
|
let gclue_manager = geoclue::ManagerProxy::new(&conn).await?;
|
|
- let gclue_client = gclue_manager.get_client().await?;
|
|
+ let gclue_client = timeout(timeout_s, gclue_manager.get_client())
|
|
+ .await
|
|
+ .context("Failed to connect to geoclue")??;
|
|
gclue_client.set_desktop_id("automatic-timezoned").await?;
|
|
gclue_client.set_distance_threshold(10000).await?; // meters
|
|
gclue_client
|
|
@@ -91,6 +100,15 @@ async fn main() -> Result<()> {
|
|
|
|
gclue_client.start().await?;
|
|
|
|
+ // Wait for first update with timeout set, to ensure it works
|
|
+ if let Some(signal) = timeout(timeout_s, location_updated.next())
|
|
+ .await
|
|
+ .context("Failed to get initial location")?
|
|
+ {
|
|
+ handle_location(signal, &timedate, &zone_finder, &conn).await?
|
|
+ }
|
|
+
|
|
+ // Wait for future updates
|
|
while let Some(signal) = location_updated.next().await {
|
|
handle_location(signal, &timedate, &zone_finder, &conn).await?
|
|
}
|
|
diff --git a/tests/cmd/help.md b/tests/cmd/help.md
|
|
index f8cfb02..f39628c 100644
|
|
--- a/tests/cmd/help.md
|
|
+++ b/tests/cmd/help.md
|
|
@@ -9,9 +9,10 @@ Automatically update system timezone based on location
|
|
Usage: automatic-timezoned [OPTIONS]
|
|
|
|
Options:
|
|
- -l, --log-level <LOG_LEVEL> Log level filter. See <https://docs.rs/env_logger> for syntax [env: AUTOTZD_LOG_LEVEL=] [default: info]
|
|
- -h, --help Print help
|
|
- -V, --version Print version
|
|
+ -l, --log-level <LOG_LEVEL> Log level filter. See <https://docs.rs/env_logger> for syntax [env: AUTOTZD_LOG_LEVEL=] [default: info]
|
|
+ -t, --timeout-secs <TIMEOUT_SECS> Timeout in seconds for connections [env: AUTOTZD_TIMEOUT_SECS=] [default: 30]
|
|
+ -h, --help Print help
|
|
+ -V, --version Print version
|
|
|
|
```
|
|
|
|
@@ -24,8 +25,9 @@ Automatically update system timezone based on location
|
|
Usage: automatic-timezoned [OPTIONS]
|
|
|
|
Options:
|
|
- -l, --log-level <LOG_LEVEL> Log level filter. See <https://docs.rs/env_logger> for syntax [env: AUTOTZD_LOG_LEVEL=] [default: info]
|
|
- -h, --help Print help
|
|
- -V, --version Print version
|
|
+ -l, --log-level <LOG_LEVEL> Log level filter. See <https://docs.rs/env_logger> for syntax [env: AUTOTZD_LOG_LEVEL=] [default: info]
|
|
+ -t, --timeout-secs <TIMEOUT_SECS> Timeout in seconds for connections [env: AUTOTZD_TIMEOUT_SECS=] [default: 30]
|
|
+ -h, --help Print help
|
|
+ -V, --version Print version
|
|
|
|
```
|
|
--
|
|
2.52.0
|
|
|