diff --git a/Cargo.lock b/Cargo.lock index fe5c7a4..2f8f32b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "argh" @@ -72,6 +72,17 @@ dependencies = [ "serde", ] +[[package]] +name = "cc" +version = "1.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -155,6 +166,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -211,6 +233,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "gethostname" version = "0.2.3" @@ -221,6 +252,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -236,6 +282,113 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -254,6 +407,7 @@ dependencies = [ "bytesize", "cli-clipboard", "colored", + "git2", "local-ip-address", "parse-size", "serde", @@ -268,6 +422,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -280,12 +443,58 @@ version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +[[package]] +name = "libgit2-sys" +version = "0.18.1+1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "local-ip-address" version = "0.6.3" @@ -425,6 +634,24 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_pipe" version = "1.2.0" @@ -441,6 +668,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487f2ccd1e17ce8c1bfab3a65c89525af41cfad4c8659021a1e9a2aacd73b89b" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "petgraph" version = "0.6.5" @@ -457,6 +690,15 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -555,12 +797,24 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "str-buf" version = "1.0.6" @@ -589,6 +843,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "sysinfo" version = "0.33.0" @@ -635,6 +900,16 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tree_magic_mini" version = "3.1.5" @@ -655,6 +930,29 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "walkdir" version = "2.5.0" @@ -983,6 +1281,12 @@ dependencies = [ "wayland-protocols", ] +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + [[package]] name = "x11-clipboard" version = "0.7.1" @@ -1019,3 +1323,81 @@ name = "xml-rs" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] diff --git a/Cargo.toml b/Cargo.toml index 93469e3..d59a470 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,5 @@ parse-size = "1.1.0" walkdir = "2" serde = "1.0.216" serde_json = "1.0.133" -colored = "2.1.0" \ No newline at end of file +colored = "2.1.0" +git2 = "0.20.2" diff --git a/README.md b/README.md index 074f500..2e82b65 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,15 @@ in large --min 1k --sort 5.7 MB ./target/release/deps/libserde-8238757ab41c1ecb.rlib ``` +Filter by file extension: + +```bash +in large --min 1k --ext rs +2.1 KB ./src/main.rs +3.4 KB ./src/args.rs +4.2 KB ./src/show_file_size.rs +``` + ### Dir mark ```bash diff --git a/src/args.rs b/src/args.rs index 7fd6211..02c7fda 100644 --- a/src/args.rs +++ b/src/args.rs @@ -17,6 +17,7 @@ pub enum InspectionCommand { ShowWorkingDirectory(InspectForWorkingDirectory), ListFileSize(InspectForFileSize), DirMark(InspectForDirMark), + FinishBranch(InspectForFinishBranch), } /// command for inspecting IP addresses. @@ -69,6 +70,9 @@ pub struct InspectForFileSize { /// show sorted result #[argh(switch, short = 's')] pub sort: bool, + /// filter by file extension (e.g., "rs", "txt") + #[argh(option)] + pub ext: Option, } /// command for directory marks @@ -79,6 +83,12 @@ pub struct InspectForDirMark { pub subcommand: DirMarkCommand, } +// InspectForFinishBranch +/// command for finishing a branch +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "finbr")] +pub struct InspectForFinishBranch {} + #[derive(FromArgs, PartialEq, Debug)] #[argh(subcommand)] pub enum DirMarkCommand { diff --git a/src/git.rs b/src/git.rs new file mode 100644 index 0000000..6fbc5a5 --- /dev/null +++ b/src/git.rs @@ -0,0 +1,130 @@ +use git2::{BranchType, Repository}; +use std::io::{self, Write}; +use std::process::Command; + +/// detect main or master branch first, get current branch, +/// then fetch origin/main --prune, switch to main, pull latest changes +/// finally delete that branch +pub fn finish_branch() -> Result<(), Box> { + let repo = Repository::open(".")?; + + // Get the current branch + let head = repo.head()?; + let current_branch_name = if let Some(name) = head.shorthand() { + name.to_string() + } else { + return Err("Not on a branch".into()); + }; + + // Check if we're already on main or master + if current_branch_name == "main" || current_branch_name == "master" { + println!("Already on {} branch, nothing to do", current_branch_name); + return Ok(()); + } + + // Detect the main branch (main or master) + let main_branch = detect_main_branch(&repo)?; + println!("Detected main branch: {}", main_branch); + + // Switch to main branch + println!("Switching to {} branch...", main_branch); + checkout_branch(&repo, &main_branch)?; + + // Fetch and pull latest changes on main branch in one operation + println!("Fetching and pulling latest changes on {} branch...", main_branch); + fetch_and_pull(&repo, &main_branch)?; + + // Delete the feature branch + print!("Delete branch '{}'? (y/N): ", current_branch_name); + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + + if input.trim().to_lowercase() == "y" || input.trim().to_lowercase() == "yes" { + delete_branch(&repo, ¤t_branch_name)?; + println!("Deleted branch '{}'", current_branch_name); + } else { + println!("Branch '{}' was not deleted", current_branch_name); + } + + println!("Finished! You are now on the {} branch", main_branch); + Ok(()) +} + +fn detect_main_branch(repo: &Repository) -> Result> { + // First try to find main branch + if repo.find_branch("main", BranchType::Local).is_ok() { + return Ok("main".to_string()); + } + + // Then try master branch + if repo.find_branch("master", BranchType::Local).is_ok() { + return Ok("master".to_string()); + } + + // Try to find remote main/master branches + let branches = repo.branches(Some(BranchType::Remote))?; + for branch_result in branches { + let (branch, _) = branch_result?; + if let Some(name) = branch.name()? { + if name.ends_with("/main") { + return Ok("main".to_string()); + } else if name.ends_with("/master") { + return Ok("master".to_string()); + } + } + } + + Err("Could not detect main or master branch".into()) +} + +fn fetch_and_pull(_repo: &Repository, main_branch: &str) -> Result<(), Box> { + // Check if there are uncommitted changes first + let status = Command::new("git").args(["status", "--porcelain"]).output()?; + if !status.stdout.is_empty() { + return Err("There are uncommitted changes. Please commit or stash them first.".into()); + } + + // Fetch all branches with prune and then merge the remote tracking branch + // This is more efficient than separate fetch + pull commands + let status = Command::new("git").args(["fetch", "origin", "--prune"]).status()?; + + if !status.success() { + return Err(format!("Failed to fetch from origin with exit code: {}", status.code().unwrap_or(-1)).into()); + } + + // Now merge the remote tracking branch (equivalent to pull but without redundant fetch) + let status = Command::new("git").args(["merge", &format!("origin/{}", main_branch)]).status()?; + + if !status.success() { + return Err( + format!( + "Failed to merge origin/{} with exit code: {}", + main_branch, + status.code().unwrap_or(-1) + ) + .into(), + ); + } + + println!("Successfully fetched and updated {} branch", main_branch); + Ok(()) +} + +fn checkout_branch(repo: &Repository, branch_name: &str) -> Result<(), Box> { + let branch = repo.find_branch(branch_name, BranchType::Local)?; + let branch_ref = branch.get(); + let commit = branch_ref.peel_to_commit()?; + + repo.checkout_tree(commit.as_object(), None)?; + repo.set_head(&format!("refs/heads/{}", branch_name))?; + + Ok(()) +} + +fn delete_branch(repo: &Repository, branch_name: &str) -> Result<(), Box> { + let mut branch = repo.find_branch(branch_name, BranchType::Local)?; + branch.delete()?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index fa04b51..1230c31 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod args; mod dir_marks; +mod git; mod show_file_size; use sysinfo::System; @@ -115,6 +116,12 @@ fn main() -> Result<(), String> { dir_marks::DirMarks::shell_fn(); } }, + FinishBranch(_) => { + if let Err(e) = git::finish_branch() { + eprintln!("Error finishing branch: {}", e); + std::process::exit(1); + } + } } Ok(()) diff --git a/src/show_file_size.rs b/src/show_file_size.rs index 40fac0f..fcd88d5 100644 --- a/src/show_file_size.rs +++ b/src/show_file_size.rs @@ -1,5 +1,6 @@ use bytesize::ByteSize; use parse_size::parse_size; +use std::path::Path; use crate::args::InspectForFileSize; use walkdir::WalkDir; @@ -7,10 +8,35 @@ use walkdir::WalkDir; pub fn show_file_size(options: InspectForFileSize) -> Result<(), String> { let min_size = parse_size(&options.min).unwrap_or_else(|_| panic!("parse file size from string: {}", &options.min)); + // Helper function to check if file matches extension filter + let matches_extension = |path: &Path| -> bool { + match &options.ext { + Some(ext) => { + if let Some(file_ext) = path.extension() { + file_ext.to_string_lossy().to_lowercase() == ext.to_lowercase() + } else { + false + } + } + None => true, // No filter, include all files + } + }; + if options.sort { let mut file_and_size: Vec<(u64, String)> = Vec::new(); - for entry in WalkDir::new(options.base) { + for entry in WalkDir::new(&options.base) { let entry = entry.map_err(|e| e.to_string())?; + + // Skip directories + if entry.file_type().is_dir() { + continue; + } + + // Check extension filter + if !matches_extension(entry.path()) { + continue; + } + // get file size let the_size = entry.metadata().map_err(|e| e.to_string())?.len(); if the_size < min_size { @@ -23,8 +49,19 @@ pub fn show_file_size(options: InspectForFileSize) -> Result<(), String> { println!("{} {}", ByteSize(size), path); } } else { - for entry in WalkDir::new(options.base) { + for entry in WalkDir::new(&options.base) { let entry = entry.map_err(|e| e.to_string())?; + + // Skip directories + if entry.file_type().is_dir() { + continue; + } + + // Check extension filter + if !matches_extension(entry.path()) { + continue; + } + // get file size let the_size = entry.metadata().map_err(|e| e.to_string())?.len(); if the_size < min_size {