From d043c384e71e8e8a7a3dd3399eef90a2ed4bf873 Mon Sep 17 00:00:00 2001
From: Michael Gattozzi <mgattozzi@gmail.com>
Date: Wed, 18 Apr 2018 17:09:28 -0400
Subject: [PATCH] feat(refactor/early abort): Exit early on failure

This commit does quite a few things in order to get this to work:

1. We move all of the code dealing with knowing which command to run
   into it's own function. This wrapper command allows us to always
   close out PBAR before dumping error output. This fixes a problem
   where stderr and stdout were borked and not printing out error
   messages correctly.
2. We then refactor the code that has a panic to return early with that
   error message.
3. If the command we ran errored, we print out with PBAR that there was
   an error with the program we ran (not wasm-pack itself) then dump the
   stderr from the command to the actual stderr

This means we can abort early on without continuing any of the other
parts of wasm-pack and let the user know what the error was rather than
just saying "There's an error"
---
 src/bindgen.rs                       |  29 +++--
 src/build.rs                         |  31 ++---
 src/command.rs                       |  42 +++++--
 src/lib.rs                           |   1 +
 src/main.rs                          |  14 +--
 src/npm.rs                           |  27 ++--
 tests/fixtures/no-compile/Cargo.lock | 176 +++++++++++++++++++++++++++
 tests/fixtures/no-compile/Cargo.toml |  13 ++
 tests/fixtures/no-compile/README.md  |   2 +
 tests/fixtures/no-compile/src/lib.rs |  15 +++
 10 files changed, 288 insertions(+), 62 deletions(-)
 create mode 100644 tests/fixtures/no-compile/Cargo.lock
 create mode 100644 tests/fixtures/no-compile/Cargo.toml
 create mode 100644 tests/fixtures/no-compile/README.md
 create mode 100644 tests/fixtures/no-compile/src/lib.rs

diff --git a/src/bindgen.rs b/src/bindgen.rs
index 19cafeb..8517b26 100644
--- a/src/bindgen.rs
+++ b/src/bindgen.rs
@@ -1,24 +1,31 @@
 use console::style;
 use emoji;
+use failure::Error;
 use std::process::Command;
 use PBAR;
 
-pub fn cargo_install_wasm_bindgen() {
+pub fn cargo_install_wasm_bindgen() -> Result<(), Error> {
     let step = format!(
         "{} {}Installing WASM-bindgen...",
         style("[6/7]").bold().dim(),
         emoji::DOWN_ARROW
     );
     let pb = PBAR.message(&step);
-    let _output = Command::new("cargo")
+    let output = Command::new("cargo")
         .arg("install")
         .arg("wasm-bindgen")
-        .output()
-        .unwrap_or_else(|e| panic!("{} failed to execute process: {}", emoji::ERROR, e));
+        .output()?;
     pb.finish();
+    if !output.status.success() {
+        let s = String::from_utf8_lossy(&output.stderr);
+        PBAR.error("npm_publish failed");
+        bail!(format!("stderr was {}", s));
+    } else {
+        Ok(())
+    }
 }
 
-pub fn wasm_bindgen_build(path: &str, name: &str) {
+pub fn wasm_bindgen_build(path: &str, name: &str) -> Result<(), Error> {
     let step = format!(
         "{} {}Running WASM-bindgen...",
         style("[7/7]").bold().dim(),
@@ -27,12 +34,18 @@ pub fn wasm_bindgen_build(path: &str, name: &str) {
     let pb = PBAR.message(&step);
     let binary_name = name.replace("-", "_");
     let wasm_path = format!("target/wasm32-unknown-unknown/release/{}.wasm", binary_name);
-    let _output = Command::new("wasm-bindgen")
+    let output = Command::new("wasm-bindgen")
         .current_dir(path)
         .arg(&wasm_path)
         .arg("--out-dir")
         .arg("./pkg")
-        .output()
-        .unwrap_or_else(|e| panic!("{} failed to execute process: {}", emoji::ERROR, e));
+        .output()?;
     pb.finish();
+    if !output.status.success() {
+        let s = String::from_utf8_lossy(&output.stderr);
+        PBAR.error("npm_publish failed");
+        bail!(format!("stderr was {}", s));
+    } else {
+        Ok(())
+    }
 }
diff --git a/src/build.rs b/src/build.rs
index aa3b807..eb3a0ab 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,9 +1,10 @@
 use console::style;
 use emoji;
+use failure::Error;
 use std::process::Command;
 use PBAR;
 
-pub fn rustup_add_wasm_target() {
+pub fn rustup_add_wasm_target() -> Result<(), Error> {
     let step = format!(
         "{} {}Adding WASM target...",
         style("[1/7]").bold().dim(),
@@ -14,21 +15,18 @@ pub fn rustup_add_wasm_target() {
         .arg("target")
         .arg("add")
         .arg("wasm32-unknown-unknown")
-        .output()
-        .unwrap_or_else(|e| panic!("{} failed to execute process: {}", emoji::ERROR, e));
+        .output()?;
     pb.finish();
     if !output.status.success() {
         let s = String::from_utf8_lossy(&output.stderr);
-
-        print!(
-            "{}  rustup_add_wasm_target failed and stderr was:\n{}",
-            emoji::ERROR,
-            s
-        );
+        PBAR.error("rustup_add_wasm_target failed");
+        bail!(format!("stderr was {}", s));
+    } else {
+        Ok(())
     }
 }
 
-pub fn cargo_build_wasm(path: &str) {
+pub fn cargo_build_wasm(path: &str) -> Result<(), Error> {
     let step = format!(
         "{} {}Compiling to WASM...",
         style("[2/7]").bold().dim(),
@@ -41,16 +39,13 @@ pub fn cargo_build_wasm(path: &str) {
         .arg("--release")
         .arg("--target")
         .arg("wasm32-unknown-unknown")
-        .output()
-        .unwrap_or_else(|e| panic!("{} failed to execute process: {}", emoji::ERROR, e));
+        .output()?;
     pb.finish();
     if !output.status.success() {
         let s = String::from_utf8_lossy(&output.stderr);
-
-        print!(
-            "{}  cargo_build_wasm failed and stderr was:\n{}",
-            emoji::ERROR,
-            s
-        );
+        PBAR.error("cargo_build_wasm failed");
+        bail!(format!("stderr was {}", s));
+    } else {
+        Ok(())
     }
 }
diff --git a/src/command.rs b/src/command.rs
index 0abde7b..38f4f05 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -6,6 +6,7 @@ use failure::Error;
 use indicatif::HumanDuration;
 use manifest;
 use npm;
+#[allow(unused)]
 use quicli::prelude::*;
 use readme;
 use std::fs;
@@ -30,6 +31,24 @@ pub enum Command {
     Publish { path: Option<String> },
 }
 
+pub fn run_wasm_pack(command: Command) -> result::Result<(), Error> {
+    // Run the correct command based off input and store the result of it so that we can clear
+    // the progress bar then return it
+    let status = match command {
+        Command::Init { path, scope } => init(path, scope),
+        Command::Pack { path } => pack(path),
+        Command::Publish { path } => publish(path),
+    };
+
+    // Make sure we always clear the progress bar before we abort the program otherwise
+    // stderr and stdout output get eaten up and nothing will work. If this part fails
+    // to work and clear the progress bars then you're really having a bad day with your tools.
+    PBAR.done()?;
+
+    // Return the actual status of the program to the main function
+    status
+}
+
 // quicli::prelude::* imports a different result struct which gets
 // precedence over the std::result::Result, so have had to specify
 // the correct type here.
@@ -46,19 +65,19 @@ pub fn create_pkg_dir(path: &str) -> result::Result<(), Error> {
     Ok(())
 }
 
-pub fn init(path: Option<String>, scope: Option<String>) -> result::Result<(), Error> {
+fn init(path: Option<String>, scope: Option<String>) -> result::Result<(), Error> {
     let started = Instant::now();
 
     let crate_path = set_crate_path(path);
 
-    build::rustup_add_wasm_target();
-    build::cargo_build_wasm(&crate_path);
+    build::rustup_add_wasm_target()?;
+    build::cargo_build_wasm(&crate_path)?;
     create_pkg_dir(&crate_path)?;
     manifest::write_package_json(&crate_path, scope)?;
     readme::copy_from_crate(&crate_path)?;
-    bindgen::cargo_install_wasm_bindgen();
+    bindgen::cargo_install_wasm_bindgen()?;
     let name = manifest::get_crate_name(&crate_path)?;
-    bindgen::wasm_bindgen_build(&crate_path, &name);
+    bindgen::wasm_bindgen_build(&crate_path, &name)?;
     PBAR.one_off_message(&format!(
         "{} Done in {}",
         emoji::SPARKLE,
@@ -69,23 +88,22 @@ pub fn init(path: Option<String>, scope: Option<String>) -> result::Result<(), E
         emoji::PACKAGE,
         &crate_path
     ));
-    PBAR.done()?;
     Ok(())
 }
 
-pub fn pack(path: Option<String>) -> result::Result<(), Error> {
+fn pack(path: Option<String>) -> result::Result<(), Error> {
     let crate_path = set_crate_path(path);
 
-    npm::npm_pack(&crate_path);
-    println!("🎒  packed up your package!");
+    npm::npm_pack(&crate_path)?;
+    PBAR.one_off_message("🎒  packed up your package!");
     Ok(())
 }
 
-pub fn publish(path: Option<String>) -> result::Result<(), Error> {
+fn publish(path: Option<String>) -> result::Result<(), Error> {
     let crate_path = set_crate_path(path);
 
-    npm::npm_publish(&crate_path);
-    println!("💥  published your package!");
+    npm::npm_publish(&crate_path)?;
+    PBAR.one_off_message("💥  published your package!");
     Ok(())
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 46009a9..e9b6f6f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,5 @@
 extern crate console;
+#[macro_use]
 extern crate failure;
 extern crate indicatif;
 #[macro_use]
diff --git a/src/main.rs b/src/main.rs
index 2b4caa0..26a5d9d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,17 +5,9 @@ extern crate indicatif;
 extern crate quicli;
 
 use quicli::prelude::*;
-use wasm_pack::command::{init, pack, publish, Command};
+use wasm_pack::command::run_wasm_pack;
 use wasm_pack::Cli;
 
-main!(|args: Cli, log_level: verbosity| match args.cmd {
-    Command::Init { path, scope } => {
-        init(path, scope)?;
-    }
-    Command::Pack { path } => {
-        pack(path)?;
-    }
-    Command::Publish { path } => {
-        publish(path)?;
-    }
+main!(|args: Cli, log_level: verbosity| {
+    run_wasm_pack(args.cmd)?;
 });
diff --git a/src/npm.rs b/src/npm.rs
index 75660c2..791e98e 100644
--- a/src/npm.rs
+++ b/src/npm.rs
@@ -1,32 +1,33 @@
-use emoji;
+use failure::Error;
 use std::process::Command;
+use PBAR;
 
-pub fn npm_pack(path: &str) {
+pub fn npm_pack(path: &str) -> Result<(), Error> {
     let pkg_file_path = format!("{}/pkg", path);
     let output = Command::new("npm")
         .current_dir(pkg_file_path)
         .arg("pack")
-        .output()
-        .unwrap_or_else(|e| panic!("{} failed to execute process: {}", emoji::ERROR, e));
+        .output()?;
     if !output.status.success() {
         let s = String::from_utf8_lossy(&output.stderr);
-        print!("{}  npm_pack failed and stderr was:\n{}", emoji::ERROR, s);
+        PBAR.error("npm_pack failed");
+        bail!(format!("stderr was {}", s));
+    } else {
+        Ok(())
     }
 }
 
-pub fn npm_publish(path: &str) {
+pub fn npm_publish(path: &str) -> Result<(), Error> {
     let pkg_file_path = format!("{}/pkg", path);
     let output = Command::new("npm")
         .current_dir(pkg_file_path)
         .arg("publish")
-        .output()
-        .unwrap_or_else(|e| panic!("{} failed to execute process: {}", emoji::ERROR, e));
+        .output()?;
     if !output.status.success() {
         let s = String::from_utf8_lossy(&output.stderr);
-        print!(
-            "{}  npm_publish failed and stderr was:\n{}",
-            emoji::ERROR,
-            s
-        );
+        PBAR.error("npm_publish failed");
+        bail!(format!("stderr was {}", s));
+    } else {
+        Ok(())
     }
 }
diff --git a/tests/fixtures/no-compile/Cargo.lock b/tests/fixtures/no-compile/Cargo.lock
new file mode 100644
index 0000000..2f53a87
--- /dev/null
+++ b/tests/fixtures/no-compile/Cargo.lock
@@ -0,0 +1,176 @@
+[[package]]
+name = "dtoa"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "itoa"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "no-compile"
+version = "0.1.0"
+dependencies = [
+ "wasm-bindgen 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro2"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "0.12.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "wasm-bindgen-macro 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-shared 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-backend 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-shared 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[metadata]
+"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
+"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
+"checksum num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c2bd9b9d21e48e956b763c9f37134dc62d9e95da6edb3f672cacb6caf3cd3"
+"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
+"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
+"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
+"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
+"checksum serde 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c73f63e08b33f6e59dfb3365b009897ebc3a3edc4af6e4f3ce8e483cf3d80ce7"
+"checksum serde_derive 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9cd9e89b8be5b611971734eaf887f1da0ce1a5b51491f04b09fe855649a84f3b"
+"checksum serde_derive_internals 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a79b781fe5c4a7037a10a485249a499ea02927046360afe7e04885aad2f9c10c"
+"checksum serde_json 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fab6c4d75bedcf880711c85e39ebf8ccc70d0eba259899047ec5d7436643ee17"
+"checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd"
+"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum wasm-bindgen 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3d40bb360252b92b57cf5ee800c92d30ae842e41d3d84bcc4fc1d3deb72d5b02"
+"checksum wasm-bindgen-backend 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f1a0ad26bc8fac6cbf68097e3dd4ffa40a288dda34e83bfaa7ff4626b69085d"
+"checksum wasm-bindgen-macro 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3a600fa1ce92e2e8db8f89a15baf679e5bac39561e55e750cda9fb6a317e64c3"
+"checksum wasm-bindgen-shared 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "aba2057a4e843cb2d754a923d46bb62aeab1531c58a78160f392e7ded8de3637"
diff --git a/tests/fixtures/no-compile/Cargo.toml b/tests/fixtures/no-compile/Cargo.toml
new file mode 100644
index 0000000..b9b66f8
--- /dev/null
+++ b/tests/fixtures/no-compile/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "no-compile"
+description = "an example rust->wasm crate that can't compile"
+version = "0.1.0"
+authors = ["Michael Gattozzi <mgattozzi@gmail.com>"]
+license = "WTFPL"
+repository = "https://github.com/ashleygwilliams/wasm-pack"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+wasm-bindgen = "0.2.4"
diff --git a/tests/fixtures/no-compile/README.md b/tests/fixtures/no-compile/README.md
new file mode 100644
index 0000000..aad6ae3
--- /dev/null
+++ b/tests/fixtures/no-compile/README.md
@@ -0,0 +1,2 @@
+# no-compile
+> an example rust -> wasm project that won't compile!
diff --git a/tests/fixtures/no-compile/src/lib.rs b/tests/fixtures/no-compile/src/lib.rs
new file mode 100644
index 0000000..4e6418f
--- /dev/null
+++ b/tests/fixtures/no-compile/src/lib.rs
@@ -0,0 +1,15 @@
+#![feature(proc_macro, wasm_import_module, wasm_custom_section)]
+
+extern crate wasm_bindgen;
+
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen]
+extern {
+    fn alert(s: &str
+}
+
+#[wasm_bindgen]
+pub fn greet(name: &str) {
+    alert(&format!("Hello, {}!", name));
+}