exp: client host and demo app using wasm/wasmtime
diff --git a/apps/client/hello/Makefile b/apps/client/hello/Makefile
new file mode 100644
index 0000000..aca0fc7
--- /dev/null
+++ b/apps/client/hello/Makefile
@@ -0,0 +1,4 @@
+run:
+	# cd hello_rust && cargo wasi build
+	cd call_host && cargo wasi build
+	go1.18 run main.go
diff --git a/apps/client/hello/call_host/Cargo.lock b/apps/client/hello/call_host/Cargo.lock
new file mode 100644
index 0000000..73c86ce
--- /dev/null
+++ b/apps/client/hello/call_host/Cargo.lock
@@ -0,0 +1,53 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "call_host"
+version = "0.1.0"
+dependencies = [
+ "tui",
+ "wasi",
+]
+
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "tui"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96fe69244ec2af261bced1d9046a6fee6c8c2a6b0228e59e5ba39bc8ba4ed729"
+dependencies = [
+ "bitflags",
+ "cassowary",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
diff --git a/apps/client/hello/call_host/Cargo.toml b/apps/client/hello/call_host/Cargo.toml
new file mode 100644
index 0000000..6b4f30b
--- /dev/null
+++ b/apps/client/hello/call_host/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "call_host"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+tui = {version = "0.18.0", default-features = false}
+wasi = "0.11.0+wasi-snapshot-preview1"
diff --git a/apps/client/hello/call_host/src/lib.rs b/apps/client/hello/call_host/src/lib.rs
new file mode 100644
index 0000000..417445c
--- /dev/null
+++ b/apps/client/hello/call_host/src/lib.rs
@@ -0,0 +1,117 @@
+use std::error;
+use tui::{
+    layout::{Alignment},
+    widgets::{Block, BorderType, Borders},
+    Terminal,
+};
+
+
+use core::result::Result;
+use std::io::Error;
+use tui::backend::Backend;
+use tui::buffer::Cell;
+use tui::layout::Rect;
+
+extern "C" {
+    fn cursorHide();
+    fn cursorShow();
+    fn cursorSet(x: u16, y: u16);
+    fn clearScreen();
+    fn getSize() -> (i32, i32, i32, i32);
+    fn flush();
+    fn draw(x: u16, y: u16);
+}
+
+struct HostBackend {}
+
+impl Backend for HostBackend {
+    fn draw<'a, I>(&mut self, content: I) -> Result<(), Error>
+    where
+        I: Iterator<Item = (u16, u16, &'a Cell)>,
+    {
+	for i in content {
+	    let x: u16 = i.0;
+	    let y: u16 = i.1;
+	    unsafe { draw(x, y) }
+	}
+        Ok(())
+    }
+
+    fn hide_cursor(&mut self) -> Result<(), Error> {
+	unsafe { cursorHide() }
+        Ok(())
+    }
+
+    fn show_cursor(&mut self) -> Result<(), Error> {
+	unsafe { cursorShow() }
+        Ok(())
+    }
+
+    fn get_cursor(&mut self) -> Result<(u16, u16), Error> {
+        Ok((100, 100))
+    }
+
+    fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), Error> {
+	unsafe { cursorSet(x, y) }
+        Ok(())
+    }
+
+    fn clear(&mut self) -> Result<(), Error> {
+	unsafe { clearScreen() }
+        Ok(())
+    }
+
+    fn size(&self) -> Result<Rect, Error> {
+	let ws: (i32, i32, i32, i32);
+	unsafe { ws = getSize(); }
+        Ok(Rect {
+            x: ws.0 as u16,
+            y: ws.1 as u16,
+            width: ws.2 as u16,
+            height: ws.3 as u16,
+        })
+        // Ok(Rect {
+        //     x: 0,
+        //     y: 0,
+        //     width: 50,
+        //     height: 50,
+        // })
+    }
+
+    fn flush(&mut self) -> Result<(), Error> {
+	unsafe { flush() }
+        Ok(())
+    }
+}
+
+fn main() -> Result<(), Box<dyn error::Error>> {
+    let backend = HostBackend{};
+    let mut terminal = Terminal::new(backend)?;
+    let mut i: i32 = 0;
+    loop {
+	terminal.draw(|f| {
+	    let size = f.size();
+	    let block = Block::default()
+		.borders(Borders::ALL)
+		.title("Main block with round corners")
+		.title_alignment(Alignment::Center)
+		.border_type(BorderType::Rounded);
+	    f.render_widget(block, size);
+	})?;
+	i = i + 1;
+	if i > 1000 {
+	    break;
+	}
+    }
+    terminal.show_cursor()?;
+
+    Ok(())
+}
+
+struct Unused<T>(T);
+
+#[no_mangle]
+pub extern "C" fn run() {
+    // unsafe { cursorSet(10, 10) }
+    Unused(main());
+}
diff --git a/apps/client/hello/go.mod b/apps/client/hello/go.mod
new file mode 100644
index 0000000..11ee5f3
--- /dev/null
+++ b/apps/client/hello/go.mod
@@ -0,0 +1,8 @@
+module github.com/giolekva/pcloud/apps/client/hello
+
+go 1.18
+
+require (
+	github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412
+	github.com/bytecodealliance/wasmtime-go v0.36.0
+)
diff --git a/apps/client/hello/go.sum b/apps/client/hello/go.sum
new file mode 100644
index 0000000..2996660
--- /dev/null
+++ b/apps/client/hello/go.sum
@@ -0,0 +1,4 @@
+github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412 h1:vOVO0ypMfTt6tZacyI0kp+iCZb1XSNiYDqnzBWYgfe4=
+github.com/ahmetalpbalkan/go-cursor v0.0.0-20131010032410-8136607ea412/go.mod h1:AI9hp1tkp10pAlK5TCwL+7yWbRgtDm9jhToq6qij2xs=
+github.com/bytecodealliance/wasmtime-go v0.36.0 h1:B6thr7RMM9xQmouBtUqm1RpkJjuLS37m6nxX+iwsQSc=
+github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
diff --git a/apps/client/hello/hello_rust/Cargo.lock b/apps/client/hello/hello_rust/Cargo.lock
new file mode 100644
index 0000000..574e459
--- /dev/null
+++ b/apps/client/hello/hello_rust/Cargo.lock
@@ -0,0 +1,389 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bumpalo"
+version = "3.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
+
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "crossterm"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "libc",
+ "mio",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "hello_rust"
+version = "0.1.0"
+dependencies = [
+ "crossterm",
+ "tui",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.125"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
+
+[[package]]
+name = "lock_api"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
+dependencies = [
+ "libc",
+ "log",
+ "miow",
+ "ntapi",
+ "wasi",
+ "winapi",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "ntapi"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-sys",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "signal-hook"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
+
+[[package]]
+name = "syn"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tui"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96fe69244ec2af261bced1d9046a6fee6c8c2a6b0228e59e5ba39bc8ba4ed729"
+dependencies = [
+ "bitflags",
+ "cassowary",
+ "crossterm",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
diff --git a/apps/client/hello/hello_rust/Cargo.toml b/apps/client/hello/hello_rust/Cargo.toml
new file mode 100644
index 0000000..4a0ef0e
--- /dev/null
+++ b/apps/client/hello/hello_rust/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "hello_rust"
+version = "0.1.0"
+edition = "2021"
+
+# [lib]
+# crate-type = ['cdylib']
+
+[dependencies]
+tui = "0.18.0"
+crossterm = "0.23.2"
+wasm-bindgen = "0.2.80"
\ No newline at end of file
diff --git a/apps/client/hello/hello_rust/src/main.rs b/apps/client/hello/hello_rust/src/main.rs
new file mode 100644
index 0000000..ce372f9
--- /dev/null
+++ b/apps/client/hello/hello_rust/src/main.rs
@@ -0,0 +1,62 @@
+use wasm_bindgen::prelude::*;
+use crossterm::{
+    event::{DisableMouseCapture, EnableMouseCapture },
+    execute,
+    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
+};
+use std::{error::Error, io};
+use tui::{
+    backend::{CrosstermBackend},
+    layout::{Alignment},
+    widgets::{Block, BorderType, Borders},
+    Terminal,
+};
+
+fn main() -> Result<(), Box<dyn Error>> {
+    enable_raw_mode()?;
+    let mut stdout = io::stdout();
+    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
+
+    let backend = CrosstermBackend::new(stdout);
+    let mut terminal = Terminal::new(backend)?;
+    let mut i: i32 = 0;
+    loop {
+	terminal.draw(|f| {
+	    let size = f.size();
+	    let block = Block::default()
+		.borders(Borders::ALL)
+		.title("Main block with round corners")
+		.title_alignment(Alignment::Center)
+		.border_type(BorderType::Rounded);
+	    f.render_widget(block, size);
+	})?;
+	i = i + 1;
+	if i > 1000 {
+	    break;
+	}
+    }
+    // restore terminal
+    disable_raw_mode()?;
+    execute!(
+        terminal.backend_mut(),
+        LeaveAlternateScreen,
+        DisableMouseCapture
+    )?;
+    terminal.show_cursor()?;
+
+    Ok(())
+}
+
+// foo
+
+#[wasm_bindgen]
+extern "C" {
+    fn hello(s: &str);
+}
+
+struct Unused<T>(T);
+
+#[no_mangle]
+pub extern "C" fn run() {
+    Unused(main());
+}
diff --git a/apps/client/hello/main.go b/apps/client/hello/main.go
new file mode 100644
index 0000000..21cb8dd
--- /dev/null
+++ b/apps/client/hello/main.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+	"unsafe"
+
+	"github.com/ahmetalpbalkan/go-cursor"
+	"github.com/bytecodealliance/wasmtime-go"
+)
+
+type WindowSize struct {
+	Row    uint16
+	Col    uint16
+	Xpixel uint16
+	Ypixel uint16
+}
+
+func check(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
+
+func main() {
+	store := wasmtime.NewStore(wasmtime.NewEngine())
+	linker := wasmtime.NewLinker(store.Engine)
+	err := linker.DefineWasi()
+	check(err)
+	wasiConfig := wasmtime.NewWasiConfig()
+	store.SetWasi(wasiConfig)
+	err = linker.FuncNew(
+		"env",
+		"hello",
+		wasmtime.NewFuncType(
+			[]*wasmtime.ValType{wasmtime.NewValType(wasmtime.KindI32)},
+			[]*wasmtime.ValType{}),
+		func(c *wasmtime.Caller, args []wasmtime.Val) ([]wasmtime.Val, *wasmtime.Trap) {
+			if len(args) != 1 {
+				check(fmt.Errorf("%+v", args))
+			}
+			id := args[0].I32()
+			fmt.Printf("Hello %d\n", id)
+			return []wasmtime.Val{}, nil
+		})
+	check(err)
+	err = linker.FuncWrap("env", "cursorHide", func() {
+		fmt.Print(cursor.Hide())
+	})
+	check(err)
+	err = linker.FuncWrap("env", "cursorShow", func() {
+		fmt.Print(cursor.Show())
+	})
+	check(err)
+	err = linker.FuncWrap("env", "cursorSet", func(x, y int32) {
+		fmt.Print(cursor.MoveTo(int(x), int(y)))
+	})
+	check(err)
+	err = linker.FuncWrap("env", "clearScreen", func() {
+		fmt.Print(cursor.ClearEntireScreen())
+	})
+	check(err)
+	err = linker.FuncWrap("env", "flush", func() {
+		// fmt.Print(cursor.Flush())
+	})
+	check(err)
+	err = linker.FuncWrap("env", "draw", func(x, y int32) {
+		fmt.Printf("\x1b7\x1b[%d;%df%s\x1b8", x, y, ".")
+	})
+	check(err)
+	err = linker.FuncWrap("env", "getSize", func() (int32, int32, int32, int32) {
+		var ws WindowSize
+		retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
+			uintptr(syscall.Stdin),
+			uintptr(syscall.TIOCGWINSZ),
+			uintptr(unsafe.Pointer(&ws)))
+		if int(retCode) == -1 {
+			panic(errno)
+		}
+		return int32(ws.Row), int32(ws.Col), int32(ws.Xpixel), int32(ws.Ypixel)
+	})
+	check(err)
+
+	wasm, err := os.ReadFile("call_host/target/wasm32-wasi/debug/call_host.wasm")
+	check(err)
+	module, err := wasmtime.NewModule(store.Engine, wasm)
+	check(err)
+	instance, err := linker.Instantiate(store, module)
+	check(err)
+	run := instance.GetFunc(store, "run")
+	if run == nil {
+		panic("not a function")
+	}
+	_, err = run.Call(store)
+	check(err)
+}