diff --git a/examples/configapp.rs b/examples/configapp.rs
deleted file mode 100644
index a7b147a..0000000
--- a/examples/configapp.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-use std::error::Error;
-use std::io::Error as IoError;
-use std::io::ErrorKind as IoErrorKind;
-use std::path::Path;
-
-use chainerror::prelude::*;
-
-#[derive(Clone, PartialEq, Debug)]
-enum ParseError {
-    InvalidValue(u32),
-    InvalidParameter(String),
-    NoOpen,
-    NoClose,
-}
-
-impl ::std::fmt::Display for ParseError {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
-        match self {
-            ParseError::InvalidValue(a) => write!(f, "InvalidValue: {}", a),
-            ParseError::InvalidParameter(a) => write!(f, "InvalidParameter: '{}'", a),
-            ParseError::NoOpen => write!(f, "No opening '{{' in config file"),
-            ParseError::NoClose => write!(f, "No closing '}}' in config file"),
-        }
-    }
-}
-
-fn parse_config(c: String) -> Result<(), Box<Error>> {
-    if !c.starts_with('{') {
-        Err(cherr!(ParseError::NoOpen))?;
-    }
-    if !c.ends_with('}') {
-        Err(cherr!(ParseError::NoClose))?;
-    }
-    let c = &c[1..(c.len() - 1)];
-    let v = c
-        .parse::<u32>()
-        .map_err(|e| cherr!(e, ParseError::InvalidParameter(c.into())))?;
-    if v > 100 {
-        Err(cherr!(ParseError::InvalidValue(v)))?;
-    }
-    Ok(())
-}
-
-derive_str_cherr!(ConfigFileError);
-derive_str_cherr!(SeriousError);
-derive_str_cherr!(FileError);
-derive_str_cherr!(AppError);
-
-fn file_reader(_filename: &Path) -> Result<(), Box<Error>> {
-    Err(IoError::from(IoErrorKind::NotFound)).map_err(mstrerr!(FileError, "File reader error"))?;
-    Ok(())
-}
-
-fn read_config(filename: &Path) -> Result<(), Box<Error>> {
-    if filename.eq(Path::new("global.ini")) {
-        // assume we got an IO error
-        file_reader(filename).map_err(mstrerr!(
-            ConfigFileError,
-            "Error reading file {:?}",
-            filename
-        ))?;
-    }
-    // assume we read some buffer
-    if filename.eq(Path::new("local.ini")) {
-        let buf = String::from("{1000}");
-        parse_config(buf)?;
-    }
-
-    if filename.eq(Path::new("user.ini")) {
-        let buf = String::from("foo");
-        parse_config(buf)?;
-    }
-
-    if filename.eq(Path::new("user2.ini")) {
-        let buf = String::from("{foo");
-        parse_config(buf)?;
-    }
-
-    if filename.eq(Path::new("user3.ini")) {
-        let buf = String::from("{foo}");
-        parse_config(buf)?;
-    }
-
-    if filename.eq(Path::new("custom.ini")) {
-        let buf = String::from("{10}");
-        parse_config(buf)?;
-    }
-
-    if filename.eq(Path::new("essential.ini")) {
-        Err(cherr!(SeriousError("Something is really wrong".into())))?;
-    }
-
-    Ok(())
-}
-
-fn read_verbose_config(p: &str) -> Result<(), Box<Error>> {
-    eprintln!("Reading '{}' ... ", p);
-    read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
-    eprintln!("Ok reading {}", p);
-    Ok(())
-}
-
-fn start_app(debug: bool) -> Result<(), Box<Error>> {
-    for p in &[
-        "global.ini",
-        "local.ini",
-        "user.ini",
-        "user2.ini",
-        "user3.ini",
-        "custom.ini",
-        "essential.ini",
-    ] {
-        if let Err(e) = read_verbose_config(p) {
-            assert!(e.is_chain::<AppError>());
-            let app_err = e.downcast_chain_ref::<AppError>().unwrap();
-
-            if app_err.find_kind::<SeriousError>().is_some() {
-                // Bail out on SeriousError
-                eprintln!("---> Serious Error:\n{:?}", e);
-                Err(cherr!(e, AppError("Seriously".into())))?;
-            } else if let Some(cfg_error) = app_err.find_kind::<ConfigFileError>() {
-                if debug {
-                    eprintln!("{:?}\n", cfg_error);
-                } else {
-                    // Deep Error handling
-                    if let Some(chioerror) = cfg_error.find_kind::<IoError>() {
-                        let ioerror = chioerror.kind();
-                        match ioerror.kind() {
-                            IoErrorKind::NotFound => {
-                                eprint!("Ignoring missing file");
-                                if let Some(root_cause) = cfg_error.root_cause() {
-                                    eprint!(", because of: {}\n", root_cause);
-                                }
-                                eprintln!();
-                            }
-                            _ => Err(cherr!(e, AppError("Unhandled IOError".into())))?,
-                        }
-                    } else {
-                        eprintln!("ConfigFileError for: {}", e);
-                    }
-                }
-            } else {
-                if debug {
-                    eprintln!("Error reading:\n{:?}\n", e)
-                } else {
-                    eprintln!("Error reading: {}\n", e)
-                }
-            }
-        }
-        eprintln!();
-    }
-    Ok(())
-}
-
-
-fn main() -> Result<(), Box<Error>> {
-    eprintln!("Display:\n");
-    let e = start_app(false).unwrap_err();
-    assert!(e.is_chain::<AppError>());
-    eprintln!("\n\n==================================");
-    eprintln!("====    Debug output");
-    eprintln!("==================================\n");
-    let r = start_app(true);
-
-    eprintln!("\n\n==================================");
-    eprintln!("====    Main return output");
-    eprintln!("==================================\n");
-    r
-}
diff --git a/examples/tutorial1.rs b/examples/tutorial1.rs
new file mode 100644
index 0000000..17d5534
--- /dev/null
+++ b/examples/tutorial1.rs
@@ -0,0 +1,34 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial1
+Error: StringError("func1 error")
+~~~
+
+!*/
+
+use std::error::Error;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err("do_some_io error")?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    if let Err(_) = do_some_io() {
+        Err("func2 error")?;
+    }
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    if let Err(_) = func2() {
+        Err("func1 error")?;
+    }
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    func1()
+}
diff --git a/examples/tutorial10.rs b/examples/tutorial10.rs
new file mode 100644
index 0000000..282fbb6
--- /dev/null
+++ b/examples/tutorial10.rs
@@ -0,0 +1,74 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial10
+Main Error Report: func1 error calling func2
+Error reported by Func2Error: Error reading 'foo.txt'
+
+Debug Error:
+examples/tutorial10.rs:49: Func2
+Caused by:
+examples/tutorial10.rs:29: Func2Error(Error reading 'foo.txt')
+Caused by:
+Kind(NotFound)
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+derive_str_cherr!(Func2Error);
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
+    Ok(())
+}
+
+#[derive(Debug)]
+enum Func1Error {
+    Func2,
+    IO(String),
+}
+
+impl ::std::fmt::Display for Func1Error {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        match self {
+            Func1Error::Func2 => write!(f, "func1 error calling func2"),
+            Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
+        }
+    }
+}
+
+fn func1() -> ChainResult<(), Func1Error> {
+    func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
+    let filename = String::from("bar.txt");
+    do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        match e.kind() {
+            Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
+            Func1Error::IO(filename) => {
+                eprintln!("Main Error Report: func1 error reading '{}'", filename)
+            }
+        }
+
+        if let Some(e) = e.find_chain_cause::<Func2Error>() {
+            eprintln!("Error reported by Func2Error: {}", e)
+        }
+
+        eprintln!("\nDebug Error:\n{:?}", e);
+    }
+    Ok(())
+}
diff --git a/examples/tutorial11.rs b/examples/tutorial11.rs
new file mode 100644
index 0000000..dd80482
--- /dev/null
+++ b/examples/tutorial11.rs
@@ -0,0 +1,79 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial11
+Main Error Report: func1 error calling func2
+Error reported by Func2Error: Error reading 'foo.txt'
+
+Debug Error:
+examples/tutorial11.rs:57: func1 error calling func2
+Caused by:
+examples/tutorial11.rs:32: Func2Error(Error reading 'foo.txt')
+Caused by:
+Kind(NotFound)
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+derive_str_cherr!(Func2Error);
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
+    Ok(())
+}
+
+enum Func1Error {
+    Func2,
+    IO(String),
+}
+
+impl ::std::fmt::Display for Func1Error {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        match self {
+            Func1Error::Func2 => write!(f, "func1 error calling func2"),
+            Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
+        }
+    }
+}
+
+impl ::std::fmt::Debug for Func1Error {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(f, "{}", self)
+    }
+}
+
+fn func1() -> ChainResult<(), Func1Error> {
+    func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
+    let filename = String::from("bar.txt");
+    do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        match e.kind() {
+            Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
+            Func1Error::IO(filename) => {
+                eprintln!("Main Error Report: func1 error reading '{}'", filename)
+            }
+        }
+
+        if let Some(e) = e.find_chain_cause::<Func2Error>() {
+            eprintln!("Error reported by Func2Error: {}", e)
+        }
+
+        eprintln!("\nDebug Error:\n{:?}", e);
+    }
+    Ok(())
+}
diff --git a/examples/tutorial2.rs b/examples/tutorial2.rs
new file mode 100644
index 0000000..2e076c4
--- /dev/null
+++ b/examples/tutorial2.rs
@@ -0,0 +1,39 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial2
+Error: examples/tutorial2.rs:28: "func1 error"
+Caused by:
+examples/tutorial2.rs:21: "func2 error"
+Caused by:
+StringError("do_some_io error")
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err("do_some_io error")?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    if let Err(e) = do_some_io() {
+        Err(cherr!(e, "func2 error"))?;
+    }
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    if let Err(e) = func2() {
+        Err(cherr!(e, "func1 error"))?;
+    }
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    func1()
+}
diff --git a/examples/tutorial3.rs b/examples/tutorial3.rs
new file mode 100644
index 0000000..1742cc5
--- /dev/null
+++ b/examples/tutorial3.rs
@@ -0,0 +1,38 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial3
+examples/tutorial3.rs:30: "func1 error"
+Caused by:
+examples/tutorial3.rs:25: "func2 error"
+Caused by:
+StringError("do_some_io error")
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err("do_some_io error")?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    do_some_io().map_err(|e| cherr!(e, "func2 error"))?;
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    func2().map_err(|e| cherr!(e, "func1 error"))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        eprintln!("{:?}", e);
+    }
+    Ok(())
+}
diff --git a/examples/tutorial4.rs b/examples/tutorial4.rs
new file mode 100644
index 0000000..67ddc55
--- /dev/null
+++ b/examples/tutorial4.rs
@@ -0,0 +1,38 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial4
+examples/tutorial4.rs:29: "func1 error"
+Caused by:
+examples/tutorial4.rs:24: "func2 error"
+Caused by:
+StringError("do_some_io error")
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err("do_some_io error")?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    do_some_io().map_err(mstrerr!("func2 error"))?;
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    func2().map_err(mstrerr!("func1 error"))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        eprintln!("{:?}", e);
+    }
+    Ok(())
+}
diff --git a/examples/tutorial5.rs b/examples/tutorial5.rs
new file mode 100644
index 0000000..5b7cb90
--- /dev/null
+++ b/examples/tutorial5.rs
@@ -0,0 +1,42 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial5
+Func2 failed because of 'entity not found'
+func1 error
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    if let Err(e) = func2() {
+        if let Some(s) = e.source() {
+            eprintln!("func2 failed because of '{}'", s);
+            Err(e).map_err(mstrerr!("func1 error"))?;
+        }
+    }
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        eprintln!("{}", e);
+    }
+    Ok(())
+}
diff --git a/examples/tutorial6.rs b/examples/tutorial6.rs
new file mode 100644
index 0000000..b2b3b2a
--- /dev/null
+++ b/examples/tutorial6.rs
@@ -0,0 +1,52 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial6
+Error: func1 error
+caused by: Error reading 'foo.txt'
+caused by: std::io::Error: entity not found
+of kind: std::io::ErrorKind::NotFound
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    func2().map_err(mstrerr!("func1 error"))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        eprintln!("Error: {}", e);
+        let mut s = e.as_ref();
+        while let Some(c) = s.source() {
+            if let Some(ioerror) = c.downcast_ref::<io::Error>() {
+                eprintln!("caused by: std::io::Error: {}", ioerror);
+                match ioerror.kind() {
+                    io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"),
+                    _ => {}
+                }
+            } else {
+                eprintln!("caused by: {}", c);
+            }
+            s = c;
+        }
+    }
+    Ok(())
+}
diff --git a/examples/tutorial7.rs b/examples/tutorial7.rs
new file mode 100644
index 0000000..89e002b
--- /dev/null
+++ b/examples/tutorial7.rs
@@ -0,0 +1,55 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial7
+Error: func1 error
+caused by: std::io::Error: entity not found
+of kind: std::io::ErrorKind::NotFound
+The root cause was: std::io::Error: Kind(
+    NotFound
+)
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
+    Ok(())
+}
+
+fn func1() -> Result<(), Box<Error>> {
+    func2().map_err(mstrerr!("func1 error"))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        eprintln!("Error: {}", e);
+        if let Some(s) = e.downcast_chain_ref::<String>() {
+            if let Some(ioerror) = s.find_cause::<io::Error>() {
+                eprintln!("caused by: std::io::Error: {}", ioerror);
+                match ioerror.kind() {
+                    io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"),
+                    _ => {}
+                }
+            }
+
+            if let Some(e) = s.root_cause() {
+                let ioerror = e.downcast_ref::<io::Error>().unwrap();
+                eprintln!("The root cause was: std::io::Error: {:#?}", ioerror);
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/examples/tutorial8.rs b/examples/tutorial8.rs
new file mode 100644
index 0000000..65e04d1
--- /dev/null
+++ b/examples/tutorial8.rs
@@ -0,0 +1,55 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial8
+Func1Error: func1 error
+Func2Error: Error reading 'foo.txt'
+Debug Func2Error:
+examples/tutorial8.rs:27: Func2Error(Error reading 'foo.txt')
+Caused by:
+Kind(NotFound)
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+derive_str_cherr!(Func2Error);
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
+    Ok(())
+}
+
+derive_str_cherr!(Func1Error);
+
+fn func1() -> Result<(), Box<Error>> {
+    func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
+            eprintln!("Func1Error: {}", f1err);
+
+            if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() {
+                eprintln!("Func2Error: {}", f2err);
+            }
+
+            if let Some(f2err) = f1err.find_chain_cause::<Func2Error>() {
+                eprintln!("Debug Func2Error:\n{:?}", f2err);
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/examples/tutorial9.rs b/examples/tutorial9.rs
new file mode 100644
index 0000000..b818e35
--- /dev/null
+++ b/examples/tutorial9.rs
@@ -0,0 +1,54 @@
+/*!
+
+~~~bash
+$ cargo run -q --example tutorial9
+Func1ErrorFunc2:
+examples/tutorial9.rs:37: Func1ErrorFunc2(func1 error calling func2)
+Caused by:
+examples/tutorial9.rs:29: Func2Error(Error reading 'foo.txt')
+Caused by:
+Kind(NotFound)
+~~~
+
+!*/
+
+use chainerror::prelude::*;
+use std::error::Error;
+use std::io;
+use std::result::Result;
+
+fn do_some_io() -> Result<(), Box<Error>> {
+    Err(io::Error::from(io::ErrorKind::NotFound))?;
+    Ok(())
+}
+
+derive_str_cherr!(Func2Error);
+
+fn func2() -> Result<(), Box<Error>> {
+    let filename = "foo.txt";
+    do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
+    Ok(())
+}
+
+derive_str_cherr!(Func1ErrorFunc2);
+derive_str_cherr!(Func1ErrorIO);
+
+fn func1() -> Result<(), Box<Error>> {
+    func2().map_err(mstrerr!(Func1ErrorFunc2, "func1 error calling func2"))?;
+    let filename = "bar.txt";
+    do_some_io().map_err(mstrerr!(Func1ErrorIO, "Error reading '{}'", filename))?;
+    Ok(())
+}
+
+fn main() -> Result<(), Box<Error>> {
+    if let Err(e) = func1() {
+        if let Some(s) = e.downcast_ref::<ChainError<Func1ErrorIO>>() {
+            eprintln!("Func1ErrorIO:\n{:?}", s);
+        }
+
+        if let Some(s) = try_cherr_ref!(e, Func1ErrorFunc2) {
+            eprintln!("Func1ErrorFunc2:\n{:?}", s);
+        }
+    }
+    Ok(())
+}
diff --git a/src/lib.rs b/src/lib.rs
index e621fcb..f3ec61d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,6 @@
 use std::error::Error;
 use std::fmt::{Debug, Display, Formatter, Result};
+use std::result::Result as StdResult;
 
 pub struct ChainError<T> {
     #[cfg(feature = "fileline")]
@@ -8,6 +9,8 @@ pub struct ChainError<T> {
     error_cause: Option<Box<dyn Error + 'static>>,
 }
 
+pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
+
 impl<T: 'static + Display + Debug> ChainError<T> {
     #[cfg(feature = "fileline")]
     pub fn new(
@@ -39,11 +42,11 @@ impl<T: 'static + Display + Debug> ChainError<T> {
         Some(cause)
     }
 
-    pub fn find_cause<U: Error + 'static>(&self) -> Option<&(dyn Error + 'static)> {
+    pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
         let mut cause = self as &(dyn Error + 'static);
         loop {
             if cause.is::<U>() {
-                return Some(cause);
+                return cause.downcast_ref::<U>();
             }
 
             match cause.source() {
@@ -53,7 +56,7 @@ impl<T: 'static + Display + Debug> ChainError<T> {
         }
     }
 
-    pub fn find_kind<U: 'static + Display + Debug>(&self) -> Option<&ChainError<U>> {
+    pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
         let mut cause = self as &(dyn Error + 'static);
         loop {
             if cause.is::<ChainError<U>>() {
@@ -229,6 +232,9 @@ macro_rules! mstrerr {
     ( $t:path, $v:expr $(, $more:expr)* ) => {
         |e| cherr!(e, $t (format!($v, $( $more , )* )))
     };
+    ( $v:expr $(, $more:expr)* ) => {
+        |e| cherr!(e, format!($v, $( $more , )* ))
+    };
 }
 
 #[macro_export]
@@ -245,138 +251,37 @@ macro_rules! derive_str_cherr {
                 write!(f, "{}({})", stringify!($e), self.0)
             }
         }
+        impl ::std::error::Error for $e {}
+    };
+}
+
+#[macro_export]
+macro_rules! try_cherr_ref {
+    ( $e:expr, $t:ident ) => {
+        $e.downcast_ref::<ChainError<$t>>()
+    };
+    ( $e:expr, $t:path ) => {
+        $e.downcast_ref::<ChainError<$t>>()
+    };
+}
+
+#[macro_export]
+macro_rules! try_cherr_mut {
+    ( $e:expr, $t:ident ) => {
+        $e.downcast_mut::<ChainError<$t>>()
+    };
+    ( $e:expr, $t:path ) => {
+        $e.downcast_mut::<ChainError<$t>>()
     };
 }
 
 pub mod prelude {
-    pub use super::{cherr, derive_str_cherr, mstrerr, ChainError, ChainErrorDown};
+    pub use super::{
+        cherr, derive_str_cherr, mstrerr, try_cherr_mut, try_cherr_ref, ChainError, ChainErrorDown,
+        ChainResult,
+    };
 }
 
 #[cfg(test)]
 mod tests {
-    use std::error::Error;
-    use std::io::Error as IoError;
-    use std::io::ErrorKind as IoErrorKind;
-    use std::path::Path;
-
-    use crate::prelude::*;
-
-    #[derive(Clone, PartialEq, Debug)]
-    enum ParseError {
-        InvalidValue(u32),
-        InvalidParameter(String),
-        NoOpen,
-        NoClose,
-    }
-
-    impl ::std::fmt::Display for ParseError {
-        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
-            match self {
-                ParseError::InvalidValue(a) => write!(f, "InvalidValue: {}", a),
-                ParseError::InvalidParameter(a) => write!(f, "InvalidParameter: '{}'", a),
-                ParseError::NoOpen => write!(f, "No opening '{{' in config file"),
-                ParseError::NoClose => write!(f, "No closing '}}' in config file"),
-            }
-        }
-    }
-
-    fn parse_config(c: String) -> Result<(), Box<Error>> {
-        if !c.starts_with('{') {
-            Err(cherr!(ParseError::NoOpen))?;
-        }
-        if !c.ends_with('}') {
-            Err(cherr!(ParseError::NoClose))?;
-        }
-        let c = &c[1..(c.len() - 1)];
-        let v = c
-            .parse::<u32>()
-            .map_err(|e| cherr!(e, ParseError::InvalidParameter(c.into())))?;
-        if v > 100 {
-            Err(cherr!(ParseError::InvalidValue(v)))?;
-        }
-        Ok(())
-    }
-
-    derive_str_cherr!(ConfigFileError);
-    derive_str_cherr!(SeriousError);
-    derive_str_cherr!(FileError);
-    derive_str_cherr!(AppError);
-
-    fn file_reader(_filename: &Path) -> Result<(), Box<Error>> {
-        Err(IoError::from(IoErrorKind::NotFound))
-            .map_err(mstrerr!(FileError, "File reader error"))?;
-        Ok(())
-    }
-
-    fn read_config(filename: &Path) -> Result<(), Box<Error>> {
-        if filename.eq(Path::new("global.ini")) {
-            // assume we got an IO error
-            file_reader(filename).map_err(mstrerr!(
-                ConfigFileError,
-                "Error reading file {:?}",
-                filename
-            ))?;
-        }
-        // assume we read some buffer
-        if filename.eq(Path::new("local.ini")) {
-            let buf = String::from("{1000}");
-            parse_config(buf)?;
-        }
-
-        if filename.eq(Path::new("user.ini")) {
-            let buf = String::from("foo");
-            parse_config(buf)?;
-        }
-
-        if filename.eq(Path::new("user2.ini")) {
-            let buf = String::from("{foo");
-            parse_config(buf)?;
-        }
-
-        if filename.eq(Path::new("user3.ini")) {
-            let buf = String::from("{foo}");
-            parse_config(buf)?;
-        }
-
-        if filename.eq(Path::new("custom.ini")) {
-            let buf = String::from("{10}");
-            parse_config(buf)?;
-        }
-
-        if filename.eq(Path::new("essential.ini")) {
-            Err(cherr!(SeriousError("Something is really wrong".into())))?;
-        }
-
-        Ok(())
-    }
-
-    fn read_config_pre(p: &str) -> Result<(), Box<Error>> {
-        read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
-        Ok(())
-    }
-
-    #[test]
-    fn test_chain_error() {
-        for p in &[
-            "global.ini",
-            "local.ini",
-            "user.ini",
-            "user2.ini",
-            "user3.ini",
-            "custom.ini",
-            "essential.ini",
-        ] {
-            if let Err(e) = read_config_pre(p) {
-                let app_err = e.downcast_chain_ref::<AppError>().unwrap();
-
-                match p {
-                    &"global.ini" => {
-                        assert!(app_err.find_kind::<ConfigFileError>().is_some());
-                        assert!(app_err.root_cause().unwrap().is::<IoError>());
-                    },
-                    _ => {}
-                }
-            }
-        }
-    }
 }