Struct cargo::util::command_prelude::ArgMatches
source · [−]pub struct ArgMatches<'a> { /* private fields */ }
Expand description
Used to get information about the arguments that were supplied to the program at runtime by
the user. New instances of this struct are obtained by using the App::get_matches
family of
methods.
Examples
let matches = App::new("MyApp")
.arg(Arg::with_name("out")
.long("output")
.required(true)
.takes_value(true))
.arg(Arg::with_name("debug")
.short("d")
.multiple(true))
.arg(Arg::with_name("cfg")
.short("c")
.takes_value(true))
.get_matches(); // builds the instance of ArgMatches
// to get information about the "cfg" argument we created, such as the value supplied we use
// various ArgMatches methods, such as ArgMatches::value_of
if let Some(c) = matches.value_of("cfg") {
println!("Value for -c: {}", c);
}
// The ArgMatches::value_of method returns an Option because the user may not have supplied
// that argument at runtime. But if we specified that the argument was "required" as we did
// with the "out" argument, we can safely unwrap because `clap` verifies that was actually
// used at runtime.
println!("Value for --output: {}", matches.value_of("out").unwrap());
// You can check the presence of an argument
if matches.is_present("out") {
// Another way to check if an argument was present, or if it occurred multiple times is to
// use occurrences_of() which returns 0 if an argument isn't found at runtime, or the
// number of times that it occurred, if it was. To allow an argument to appear more than
// once, you must use the .multiple(true) method, otherwise it will only return 1 or 0.
if matches.occurrences_of("debug") > 2 {
println!("Debug mode is REALLY on, don't be crazy");
} else {
println!("Debug mode kind of on");
}
}
Implementations
sourceimpl<'a> ArgMatches<'a>
impl<'a> ArgMatches<'a>
sourcepub fn value_of<S>(&self, name: S) -> Option<&str> where
S: AsRef<str>,
pub fn value_of<S>(&self, name: S) -> Option<&str> where
S: AsRef<str>,
Gets the value of a specific option or positional argument (i.e. an argument that takes
an additional value at runtime). If the option wasn’t present at runtime
it returns None
.
NOTE: If getting a value for an option or positional argument that allows multiples,
prefer ArgMatches::values_of
as ArgMatches::value_of
will only return the first
value.
Panics
This method will panic!
if the value contains invalid UTF-8 code points.
Examples
let m = App::new("myapp")
.arg(Arg::with_name("output")
.takes_value(true))
.get_matches_from(vec!["myapp", "something"]);
assert_eq!(m.value_of("output"), Some("something"));
sourcepub fn value_of_lossy<S>(&'a self, name: S) -> Option<Cow<'a, str>> where
S: AsRef<str>,
pub fn value_of_lossy<S>(&'a self, name: S) -> Option<Cow<'a, str>> where
S: AsRef<str>,
Gets the lossy value of a specific argument. If the argument wasn’t present at runtime
it returns None
. A lossy value is one which contains invalid UTF-8 code points, those
invalid points will be replaced with \u{FFFD}
NOTE: If getting a value for an option or positional argument that allows multiples,
prefer Arg::values_of_lossy
as value_of_lossy()
will only return the first value.
Examples
use std::ffi::OsString;
use std::os::unix::ffi::{OsStrExt,OsStringExt};
let m = App::new("utf8")
.arg(Arg::from_usage("<arg> 'some arg'"))
.get_matches_from(vec![OsString::from("myprog"),
// "Hi {0xe9}!"
OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!");
sourcepub fn value_of_os<S>(&self, name: S) -> Option<&OsStr> where
S: AsRef<str>,
pub fn value_of_os<S>(&self, name: S) -> Option<&OsStr> where
S: AsRef<str>,
Gets the OS version of a string value of a specific argument. If the option wasn’t present
at runtime it returns None
. An OS value on Unix-like systems is any series of bytes,
regardless of whether or not they contain valid UTF-8 code points. Since String
s in
Rust are guaranteed to be valid UTF-8, a valid filename on a Unix system as an argument
value may contain invalid UTF-8 code points.
NOTE: If getting a value for an option or positional argument that allows multiples,
prefer ArgMatches::values_of_os
as Arg::value_of_os
will only return the first
value.
Examples
use std::ffi::OsString;
use std::os::unix::ffi::{OsStrExt,OsStringExt};
let m = App::new("utf8")
.arg(Arg::from_usage("<arg> 'some arg'"))
.get_matches_from(vec![OsString::from("myprog"),
// "Hi {0xe9}!"
OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']);
sourcepub fn values_of<S>(&'a self, name: S) -> Option<Values<'a>> where
S: AsRef<str>,
pub fn values_of<S>(&'a self, name: S) -> Option<Values<'a>> where
S: AsRef<str>,
Gets a Values
struct which implements Iterator
for values of a specific argument
(i.e. an argument that takes multiple values at runtime). If the option wasn’t present at
runtime it returns None
Panics
This method will panic if any of the values contain invalid UTF-8 code points.
Examples
let m = App::new("myprog")
.arg(Arg::with_name("output")
.multiple(true)
.short("o")
.takes_value(true))
.get_matches_from(vec![
"myprog", "-o", "val1", "val2", "val3"
]);
let vals: Vec<&str> = m.values_of("output").unwrap().collect();
assert_eq!(vals, ["val1", "val2", "val3"]);
sourcepub fn values_of_lossy<S>(&'a self, name: S) -> Option<Vec<String, Global>> where
S: AsRef<str>,
pub fn values_of_lossy<S>(&'a self, name: S) -> Option<Vec<String, Global>> where
S: AsRef<str>,
Gets the lossy values of a specific argument. If the option wasn’t present at runtime
it returns None
. A lossy value is one where if it contains invalid UTF-8 code points,
those invalid points will be replaced with \u{FFFD}
Examples
use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt;
let m = App::new("utf8")
.arg(Arg::from_usage("<arg>... 'some arg'"))
.get_matches_from(vec![OsString::from("myprog"),
// "Hi"
OsString::from_vec(vec![b'H', b'i']),
// "{0xe9}!"
OsString::from_vec(vec![0xe9, b'!'])]);
let mut itr = m.values_of_lossy("arg").unwrap().into_iter();
assert_eq!(&itr.next().unwrap()[..], "Hi");
assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!");
assert_eq!(itr.next(), None);
sourcepub fn values_of_os<S>(&'a self, name: S) -> Option<OsValues<'a>> where
S: AsRef<str>,
pub fn values_of_os<S>(&'a self, name: S) -> Option<OsValues<'a>> where
S: AsRef<str>,
Gets a OsValues
struct which is implements Iterator
for OsString
values of a
specific argument. If the option wasn’t present at runtime it returns None
. An OS value
on Unix-like systems is any series of bytes, regardless of whether or not they contain
valid UTF-8 code points. Since String
s in Rust are guaranteed to be valid UTF-8, a valid
filename as an argument value on Linux (for example) may contain invalid UTF-8 code points.
Examples
use std::ffi::{OsStr,OsString};
use std::os::unix::ffi::{OsStrExt,OsStringExt};
let m = App::new("utf8")
.arg(Arg::from_usage("<arg>... 'some arg'"))
.get_matches_from(vec![OsString::from("myprog"),
// "Hi"
OsString::from_vec(vec![b'H', b'i']),
// "{0xe9}!"
OsString::from_vec(vec![0xe9, b'!'])]);
let mut itr = m.values_of_os("arg").unwrap().into_iter();
assert_eq!(itr.next(), Some(OsStr::new("Hi")));
assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!'])));
assert_eq!(itr.next(), None);
sourcepub fn is_present<S>(&self, name: S) -> bool where
S: AsRef<str>,
pub fn is_present<S>(&self, name: S) -> bool where
S: AsRef<str>,
Returns true
if an argument was present at runtime, otherwise false
.
Examples
let m = App::new("myprog")
.arg(Arg::with_name("debug")
.short("d"))
.get_matches_from(vec![
"myprog", "-d"
]);
assert!(m.is_present("debug"));
sourcepub fn occurrences_of<S>(&self, name: S) -> u64 where
S: AsRef<str>,
pub fn occurrences_of<S>(&self, name: S) -> u64 where
S: AsRef<str>,
Returns the number of times an argument was used at runtime. If an argument isn’t present
it will return 0
.
NOTE: This returns the number of times the argument was used, not the number of
values. For example, -o val1 val2 val3 -o val4
would return 2
(2 occurrences, but 4
values).
Examples
let m = App::new("myprog")
.arg(Arg::with_name("debug")
.short("d")
.multiple(true))
.get_matches_from(vec![
"myprog", "-d", "-d", "-d"
]);
assert_eq!(m.occurrences_of("debug"), 3);
This next example shows that counts actual uses of the argument, not just -
’s
let m = App::new("myprog")
.arg(Arg::with_name("debug")
.short("d")
.multiple(true))
.arg(Arg::with_name("flag")
.short("f"))
.get_matches_from(vec![
"myprog", "-ddfd"
]);
assert_eq!(m.occurrences_of("debug"), 3);
assert_eq!(m.occurrences_of("flag"), 1);
sourcepub fn index_of<S>(&self, name: S) -> Option<usize> where
S: AsRef<str>,
pub fn index_of<S>(&self, name: S) -> Option<usize> where
S: AsRef<str>,
Gets the starting index of the argument in respect to all other arguments. Indices are similar to argv indices, but are not exactly 1:1.
For flags (i.e. those arguments which don’t have an associated value), indices refer
to occurrence of the switch, such as -f
, or --flag
. However, for options the indices
refer to the values -o val
would therefore not represent two distinct indices, only the
index for val
would be recorded. This is by design.
Besides the flag/option descrepancy, the primary difference between an argv index and clap index, is that clap continues counting once all arguments have properly seperated, whereas an argv index does not.
The examples should clear this up.
NOTE: If an argument is allowed multiple times, this method will only give the first index.
Examples
The argv indices are listed in the comments below. See how they correspond to the clap
indices. Note that if it’s not listed in a clap index, this is becuase it’s not saved in
in an ArgMatches
struct for querying.
let m = App::new("myapp")
.arg(Arg::with_name("flag")
.short("f"))
.arg(Arg::with_name("option")
.short("o")
.takes_value(true))
.get_matches_from(vec!["myapp", "-f", "-o", "val"]);
// ARGV idices: ^0 ^1 ^2 ^3
// clap idices: ^1 ^3
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("option"), Some(3));
Now notice, if we use one of the other styles of options:
let m = App::new("myapp")
.arg(Arg::with_name("flag")
.short("f"))
.arg(Arg::with_name("option")
.short("o")
.takes_value(true))
.get_matches_from(vec!["myapp", "-f", "-o=val"]);
// ARGV idices: ^0 ^1 ^2
// clap idices: ^1 ^3
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("option"), Some(3));
Things become much more complicated, or clear if we look at a more complex combination of flags. Let’s also throw in the final option style for good measure.
let m = App::new("myapp")
.arg(Arg::with_name("flag")
.short("f"))
.arg(Arg::with_name("flag2")
.short("F"))
.arg(Arg::with_name("flag3")
.short("z"))
.arg(Arg::with_name("option")
.short("o")
.takes_value(true))
.get_matches_from(vec!["myapp", "-fzF", "-oval"]);
// ARGV idices: ^0 ^1 ^2
// clap idices: ^1,2,3 ^5
//
// clap sees the above as 'myapp -f -z -F -o val'
// ^0 ^1 ^2 ^3 ^4 ^5
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("flag2"), Some(3));
assert_eq!(m.index_of("flag3"), Some(2));
assert_eq!(m.index_of("option"), Some(5));
One final combination of flags/options to see how they combine:
let m = App::new("myapp")
.arg(Arg::with_name("flag")
.short("f"))
.arg(Arg::with_name("flag2")
.short("F"))
.arg(Arg::with_name("flag3")
.short("z"))
.arg(Arg::with_name("option")
.short("o")
.takes_value(true)
.multiple(true))
.get_matches_from(vec!["myapp", "-fzFoval"]);
// ARGV idices: ^0 ^1
// clap idices: ^1,2,3^5
//
// clap sees the above as 'myapp -f -z -F -o val'
// ^0 ^1 ^2 ^3 ^4 ^5
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("flag2"), Some(3));
assert_eq!(m.index_of("flag3"), Some(2));
assert_eq!(m.index_of("option"), Some(5));
The last part to mention is when values are sent in multiple groups with a delimiter.
let m = App::new("myapp")
.arg(Arg::with_name("option")
.short("o")
.takes_value(true)
.multiple(true))
.get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
// ARGV idices: ^0 ^1
// clap idices: ^2 ^3 ^4
//
// clap sees the above as 'myapp -o val1 val2 val3'
// ^0 ^1 ^2 ^3 ^4
assert_eq!(m.index_of("option"), Some(2));
sourcepub fn indices_of<S>(&'a self, name: S) -> Option<Indices<'a>> where
S: AsRef<str>,
pub fn indices_of<S>(&'a self, name: S) -> Option<Indices<'a>> where
S: AsRef<str>,
Gets all indices of the argument in respect to all other arguments. Indices are similar to argv indices, but are not exactly 1:1.
For flags (i.e. those arguments which don’t have an associated value), indices refer
to occurrence of the switch, such as -f
, or --flag
. However, for options the indices
refer to the values -o val
would therefore not represent two distinct indices, only the
index for val
would be recorded. This is by design.
NOTE: For more information about how clap indices compare to argv indices, see
ArgMatches::index_of
Examples
let m = App::new("myapp")
.arg(Arg::with_name("option")
.short("o")
.takes_value(true)
.use_delimiter(true)
.multiple(true))
.get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
// ARGV idices: ^0 ^1
// clap idices: ^2 ^3 ^4
//
// clap sees the above as 'myapp -o val1 val2 val3'
// ^0 ^1 ^2 ^3 ^4
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
Another quick example is when flags and options are used together
let m = App::new("myapp")
.arg(Arg::with_name("option")
.short("o")
.takes_value(true)
.multiple(true))
.arg(Arg::with_name("flag")
.short("f")
.multiple(true))
.get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
// ARGV idices: ^0 ^1 ^2 ^3 ^4 ^5 ^6
// clap idices: ^2 ^3 ^5 ^6
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]);
One final example, which is an odd case; if we don’t use value delimiter as we did with
the first example above instead of val1
, val2
and val3
all being distinc values, they
would all be a single value of val1,val2,val3
, in which case case they’d only receive a
single index.
let m = App::new("myapp")
.arg(Arg::with_name("option")
.short("o")
.takes_value(true)
.multiple(true))
.get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
// ARGV idices: ^0 ^1
// clap idices: ^2
//
// clap sees the above as 'myapp -o "val1,val2,val3"'
// ^0 ^1 ^2
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
sourcepub fn subcommand_matches<S>(&self, name: S) -> Option<&ArgMatches<'a>> where
S: AsRef<str>,
pub fn subcommand_matches<S>(&self, name: S) -> Option<&ArgMatches<'a>> where
S: AsRef<str>,
Because Subcommand
s are essentially “sub-App
s” they have their own ArgMatches
as well. This method returns the ArgMatches
for a particular subcommand or None
if
the subcommand wasn’t present at runtime.
Examples
let app_m = App::new("myprog")
.arg(Arg::with_name("debug")
.short("d"))
.subcommand(SubCommand::with_name("test")
.arg(Arg::with_name("opt")
.long("option")
.takes_value(true)))
.get_matches_from(vec![
"myprog", "-d", "test", "--option", "val"
]);
// Both parent commands, and child subcommands can have arguments present at the same times
assert!(app_m.is_present("debug"));
// Get the subcommand's ArgMatches instance
if let Some(sub_m) = app_m.subcommand_matches("test") {
// Use the struct like normal
assert_eq!(sub_m.value_of("opt"), Some("val"));
}
sourcepub fn subcommand_name(&self) -> Option<&str>
pub fn subcommand_name(&self) -> Option<&str>
Because Subcommand
s are essentially “sub-App
s” they have their own ArgMatches
as well.But simply getting the sub-ArgMatches
doesn’t help much if we don’t also know
which subcommand was actually used. This method returns the name of the subcommand that was
used at runtime, or None
if one wasn’t.
NOTE: Subcommands form a hierarchy, where multiple subcommands can be used at runtime, but only a single subcommand from any group of sibling commands may used at once.
An ASCII art depiction may help explain this better…Using a fictional version of git
as
the demo subject. Imagine the following are all subcommands of git
(note, the author is
aware these aren’t actually all subcommands in the real git
interface, but it makes
explanation easier)
Top Level App (git) TOP
|
-----------------------------------------
/ | \ \
clone push add commit LEVEL 1
| / \ / \ |
url origin remote ref name message LEVEL 2
/ /\
path remote local LEVEL 3
Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all inclusive list, and not including argument options per command for brevity and clarity):
$ git clone url
$ git push origin path
$ git add ref local
$ git commit message
Notice only one command per “level” may be used. You could not, for example, do $ git clone url push origin path
Examples
let app_m = App::new("git")
.subcommand(SubCommand::with_name("clone"))
.subcommand(SubCommand::with_name("push"))
.subcommand(SubCommand::with_name("commit"))
.get_matches();
match app_m.subcommand_name() {
Some("clone") => {}, // clone was used
Some("push") => {}, // push was used
Some("commit") => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}
sourcepub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>)
pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>)
This brings together ArgMatches::subcommand_matches
and ArgMatches::subcommand_name
by returning a tuple with both pieces of information.
Examples
let app_m = App::new("git")
.subcommand(SubCommand::with_name("clone"))
.subcommand(SubCommand::with_name("push"))
.subcommand(SubCommand::with_name("commit"))
.get_matches();
match app_m.subcommand() {
("clone", Some(sub_m)) => {}, // clone was used
("push", Some(sub_m)) => {}, // push was used
("commit", Some(sub_m)) => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}
Another useful scenario is when you want to support third party, or external, subcommands. In these cases you can’t know the subcommand name ahead of time, so use a variable instead with pattern matching!
// Assume there is an external subcommand named "subcmd"
let app_m = App::new("myprog")
.setting(AppSettings::AllowExternalSubcommands)
.get_matches_from(vec![
"myprog", "subcmd", "--option", "value", "-fff", "--flag"
]);
// All trailing arguments will be stored under the subcommand's sub-matches using an empty
// string argument name
match app_m.subcommand() {
(external, Some(sub_m)) => {
let ext_args: Vec<&str> = sub_m.values_of("").unwrap().collect();
assert_eq!(external, "subcmd");
assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
},
_ => {},
}
Trait Implementations
sourceimpl<'a> ArgMatchesExt for ArgMatches<'a>
impl<'a> ArgMatchesExt for ArgMatches<'a>
fn _value_of(&self, name: &str) -> Option<&str>
fn _value_of_os(&self, name: &str) -> Option<&OsStr>
fn _values_of(&self, name: &str) -> Vec<String>ⓘNotable traits for Vec<u8, A>impl<A> Write for Vec<u8, A> where
A: Allocator,
A: Allocator,
fn _values_of_os(&self, name: &str) -> Vec<OsString>ⓘNotable traits for Vec<u8, A>impl<A> Write for Vec<u8, A> where
A: Allocator,
A: Allocator,
fn _is_present(&self, name: &str) -> bool
fn value_of_u32(&self, name: &str) -> CargoResult<Option<u32>>
sourcefn value_of_path(&self, name: &str, config: &Config) -> Option<PathBuf>
fn value_of_path(&self, name: &str, config: &Config) -> Option<PathBuf>
Returns value of the name
command-line argument as an absolute path
fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf>
fn workspace<'a>(&self, config: &'a Config) -> CargoResult<Workspace<'a>>
fn jobs(&self) -> CargoResult<Option<u32>>
fn targets(&self) -> Vec<String>ⓘNotable traits for Vec<u8, A>impl<A> Write for Vec<u8, A> where
A: Allocator,
A: Allocator,
fn get_profile_name(
&self,
config: &Config,
default: &str,
profile_checking: ProfileChecking
) -> CargoResult<InternedString>
fn packages_from_flags(&self) -> CargoResult<Packages>
fn compile_options(
&self,
config: &Config,
mode: CompileMode,
workspace: Option<&Workspace<'_>>,
profile_checking: ProfileChecking
) -> CargoResult<CompileOptions>
fn cli_features(&self) -> CargoResult<CliFeatures>
fn compile_options_for_single_package(
&self,
config: &Config,
mode: CompileMode,
workspace: Option<&Workspace<'_>>,
profile_checking: ProfileChecking
) -> CargoResult<CompileOptions>
fn new_options(&self, config: &Config) -> CargoResult<NewOptions>
fn registry(&self, config: &Config) -> CargoResult<Option<String>>
fn index(&self, config: &Config) -> CargoResult<Option<String>>
fn check_optional_opts(
&self,
workspace: &Workspace<'_>,
compile_opts: &CompileOptions
) -> CargoResult<()>
fn is_present_with_zero_values(&self, name: &str) -> bool
sourceimpl<'a> Clone for ArgMatches<'a>
impl<'a> Clone for ArgMatches<'a>
sourcepub fn clone(&self) -> ArgMatches<'a>
pub fn clone(&self) -> ArgMatches<'a>
Returns a copy of the value. Read more
1.0.0 · sourcefn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source
. Read more
sourceimpl<'a> Debug for ArgMatches<'a>
impl<'a> Debug for ArgMatches<'a>
sourceimpl<'a> Default for ArgMatches<'a>
impl<'a> Default for ArgMatches<'a>
sourcepub fn default() -> ArgMatches<'a>
pub fn default() -> ArgMatches<'a>
Returns the “default value” for a type. Read more
Auto Trait Implementations
impl<'a> RefUnwindSafe for ArgMatches<'a>
impl<'a> Send for ArgMatches<'a>
impl<'a> Sync for ArgMatches<'a>
impl<'a> Unpin for ArgMatches<'a>
impl<'a> UnwindSafe for ArgMatches<'a>
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcepub fn borrow_mut(&mut self) -> &mut T
pub fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
sourceimpl<T> ToOwned for T where
T: Clone,
impl<T> ToOwned for T where
T: Clone,
type Owned = T
type Owned = T
The resulting type after obtaining ownership.
sourcepub fn to_owned(&self) -> T
pub fn to_owned(&self) -> T
Creates owned data from borrowed data, usually by cloning. Read more
sourcepub fn clone_into(&self, target: &mut T)
pub fn clone_into(&self, target: &mut T)
toowned_clone_into
)Uses borrowed data to replace owned data, usually by cloning. Read more