diff --git a/.gitignore b/.gitignore
index ff0d847..d3ae36e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
 /target
+/examples/**/target/*
 /.vscode
 Cargo.lock
+
+/flamegraph.svg
diff --git a/Cargo.toml b/Cargo.toml
index 0d48074..a691d2b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,11 +5,73 @@ version = "0.1.0"
 edition = "2021"
 publish = false
 
+[[bin]]
+name = "tokio-panic-handling"
+path = "src/bin/tokio-panic-handling.rs"
+
+[[bin]]
+name = "string-search-heaptrack"
+path = "src/bin/string-search-heaptrack.rs"
+
+[[bin]]
+name = "phrases-randomized"
+path = "src/bin/phrases-randomized.rs"
+
 [dependencies]
+anyhow = "1.0.66"
+futures = "0.3.19"
+hyper = { version = "0.14.16", features = ["full"] }
+hyper-rustls = { version = "0.23.0", features = ["http1", "http2"] }
+tokio = { version = "1.17.0", features = ["full"] }
+tokio-util = "0.7.7"
+rustls = "0.21.0"
 clap = { version = "3", features = ["derive"] }
 dotenv = "0.15.0"
 env_logger = "0.9.0"
 log = "0.4.16"
+http-body = "0.4.5"
+bufstream = "0.1.3"
+base64 = "0.21"
+imap-proto = "0.16.1"
+rustls-connector = { version = "0.18.0", features = ["dangerous-configuration"] }
+hmac = { version = "0.13.0-pre.3" }
+pbkdf2 = { version = "0.13.0-pre.0" }
+sha2 = { version = "0.11.0-pre.3" }
+hex-literal = "^0.4"
+hex = "^0.4"
+aes-gcm-siv = "^0.11"
+aes = "^0.8"
+heapless = "^0.8"
+rand = "0.8.5"
+pin-project = "1.1.7"
+nalgebra = "0.33.2"
+nom = "7.1.3"
+async-trait = "0.1.83"
+reqwest = "0.12.15"
+
+# Misc
+crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
+kanal = "0.1.0-pre8"
+
+axum = { version = "0.6.18", features = ["headers", "tower-log"] }
+axum-extra = "0.1.2"
+
+# Axum builds on the types in Tower
+tower = { version = "0.4.13", features = ["limit", "load-shed", "filter", "util"] }
+tower-http = { version = "0.4.0", features = ["trace", "cors", "catch-panic"] }
+tower-layer = "0.3.1"
+tower-service = "0.3.1"
+tower-http_0_2_4 = { package = "tower-http", version = "0.2.4" , features = ["cors"] }
+
+# Logging support
+tracing = "0.1.30"
+tracing-subscriber = { version = "0.3.8", features = ["env-filter"] }
+backon = "1.4.0"
+bytes = "1.10.1"
+thiserror = "2.0.12"
 
 [dev-dependencies]
 test-log = "0.2.10"
+
+[profile.release]
+debug = true
diff --git a/LICENSE b/LICENSE
index 03bf8a9..8092844 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,7 @@
 The MIT License (MIT)
 
-Copyright (c) 2021 Michael de Silva (https://desilva.io/about)
+Copyright (c) Michael de Silva (https://desilva.io/about)
+Email: michael@cyberdynea.io
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index 127311a..4895b46 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,13 @@
 
 This repo means to serve as a playground for expressing concepts quickly, in a "Rust by Example" format.
 
+## Examples
+
+Run the following with `cargo r --bin <PACKAGE_NAME>`
+
+1. `tokio-panic-handling`
+
+
 
 ## License Information
 
diff --git a/benchmarking/string-search/README.md b/benchmarking/string-search/README.md
new file mode 100644
index 0000000..5515249
--- /dev/null
+++ b/benchmarking/string-search/README.md
@@ -0,0 +1,19 @@
+# string-search
+
+## flamegraph
+
+Run as follows, also works on Mac.
+
+```
+cargo flamegraph --root --flamechart --verbose --bin string-search-heaptrack
+```
+
+This example runs 1 Million invocations of `Entries::search()`
+
+<img src="./flamegraph.svg"/>
+
+## heaptrack
+
+Run `./run_heaptrack.sh`.  Tested on Debian 12.
+
+Connect to a remote host using `ssh -X` to allow forwarding `heaptrack_gui`.
diff --git a/benchmarking/string-search/flamegraph.svg b/benchmarking/string-search/flamegraph.svg
new file mode 100644
index 0000000..d8aa5fd
--- /dev/null
+++ b/benchmarking/string-search/flamegraph.svg
@@ -0,0 +1,491 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" width="1200" height="310" onload="init(evt)" viewBox="0 0 1200 310" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fg="http://github.com/jonhoo/inferno"><!--Flame graph stack visualization. See https://github.com/brendangregg/FlameGraph for latest version, and http://www.brendangregg.com/flamegraphs.html for examples.--><!--NOTES: --><defs><linearGradient id="background" y1="0" y2="1" x1="0" x2="0"><stop stop-color="#eeeeee" offset="5%"/><stop stop-color="#eeeeb0" offset="95%"/></linearGradient></defs><style type="text/css">
+text { font-family:monospace; font-size:12px }
+#title { text-anchor:middle; font-size:17px; }
+#matched { text-anchor:end; }
+#search { text-anchor:end; opacity:0.1; cursor:pointer; }
+#search:hover, #search.show { opacity:1; }
+#subtitle { text-anchor:middle; font-color:rgb(160,160,160); }
+#unzoom { cursor:pointer; }
+#frames > *:hover { stroke:black; stroke-width:0.5; cursor:pointer; }
+.hide { display:none; }
+.parent { opacity:0.5; }
+</style><script type="text/ecmascript"><![CDATA[
+        var nametype = 'Function:';
+        var fontsize = 12;
+        var fontwidth = 0.59;
+        var xpad = 10;
+        var inverted = false;
+        var searchcolor = 'rgb(230,0,230)';
+        var fluiddrawing = true;
+        var truncate_text_right = false;
+    ]]><![CDATA["use strict";
+var details, searchbtn, unzoombtn, matchedtxt, svg, searching, frames, known_font_width;
+function init(evt) {
+    details = document.getElementById("details").firstChild;
+    searchbtn = document.getElementById("search");
+    unzoombtn = document.getElementById("unzoom");
+    matchedtxt = document.getElementById("matched");
+    svg = document.getElementsByTagName("svg")[0];
+    frames = document.getElementById("frames");
+    known_font_width = get_monospace_width(frames);
+    total_samples = parseInt(frames.attributes.total_samples.value);
+    searching = 0;
+
+    // Use GET parameters to restore a flamegraph's state.
+    var restore_state = function() {
+        var params = get_params();
+        if (params.x && params.y)
+            zoom(find_group(document.querySelector('[*|x="' + params.x + '"][y="' + params.y + '"]')));
+        if (params.s)
+            search(params.s);
+    };
+
+    if (fluiddrawing) {
+        // Make width dynamic so the SVG fits its parent's width.
+        svg.removeAttribute("width");
+        // Edge requires us to have a viewBox that gets updated with size changes.
+        var isEdge = /Edge\/\d./i.test(navigator.userAgent);
+        if (!isEdge) {
+            svg.removeAttribute("viewBox");
+        }
+        var update_for_width_change = function() {
+            if (isEdge) {
+                svg.attributes.viewBox.value = "0 0 " + svg.width.baseVal.value + " " + svg.height.baseVal.value;
+            }
+
+            // Keep consistent padding on left and right of frames container.
+            frames.attributes.width.value = svg.width.baseVal.value - xpad * 2;
+
+            // Text truncation needs to be adjusted for the current width.
+            update_text_for_elements(frames.children);
+
+            // Keep search elements at a fixed distance from right edge.
+            var svgWidth = svg.width.baseVal.value;
+            searchbtn.attributes.x.value = svgWidth - xpad;
+            matchedtxt.attributes.x.value = svgWidth - xpad;
+        };
+        window.addEventListener('resize', function() {
+            update_for_width_change();
+        });
+        // This needs to be done asynchronously for Safari to work.
+        setTimeout(function() {
+            unzoom();
+            update_for_width_change();
+            restore_state();
+        }, 0);
+    } else {
+        restore_state();
+    }
+}
+// event listeners
+window.addEventListener("click", function(e) {
+    var target = find_group(e.target);
+    if (target) {
+        if (target.nodeName == "a") {
+            if (e.ctrlKey === false) return;
+            e.preventDefault();
+        }
+        if (target.classList.contains("parent")) unzoom();
+        zoom(target);
+
+        // set parameters for zoom state
+        var el = target.querySelector("rect");
+        if (el && el.attributes && el.attributes.y && el.attributes["fg:x"]) {
+            var params = get_params()
+            params.x = el.attributes["fg:x"].value;
+            params.y = el.attributes.y.value;
+            history.replaceState(null, null, parse_params(params));
+        }
+    }
+    else if (e.target.id == "unzoom") {
+        unzoom();
+
+        // remove zoom state
+        var params = get_params();
+        if (params.x) delete params.x;
+        if (params.y) delete params.y;
+        history.replaceState(null, null, parse_params(params));
+    }
+    else if (e.target.id == "search") search_prompt();
+}, false)
+// mouse-over for info
+// show
+window.addEventListener("mouseover", function(e) {
+    var target = find_group(e.target);
+    if (target) details.nodeValue = nametype + " " + g_to_text(target);
+}, false)
+// clear
+window.addEventListener("mouseout", function(e) {
+    var target = find_group(e.target);
+    if (target) details.nodeValue = ' ';
+}, false)
+// ctrl-F for search
+window.addEventListener("keydown",function (e) {
+    if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) {
+        e.preventDefault();
+        search_prompt();
+    }
+}, false)
+// functions
+function get_params() {
+    var params = {};
+    var paramsarr = window.location.search.substr(1).split('&');
+    for (var i = 0; i < paramsarr.length; ++i) {
+        var tmp = paramsarr[i].split("=");
+        if (!tmp[0] || !tmp[1]) continue;
+        params[tmp[0]]  = decodeURIComponent(tmp[1]);
+    }
+    return params;
+}
+function parse_params(params) {
+    var uri = "?";
+    for (var key in params) {
+        uri += key + '=' + encodeURIComponent(params[key]) + '&';
+    }
+    if (uri.slice(-1) == "&")
+        uri = uri.substring(0, uri.length - 1);
+    if (uri == '?')
+        uri = window.location.href.split('?')[0];
+    return uri;
+}
+function find_child(node, selector) {
+    var children = node.querySelectorAll(selector);
+    if (children.length) return children[0];
+    return;
+}
+function find_group(node) {
+    var parent = node.parentElement;
+    if (!parent) return;
+    if (parent.id == "frames") return node;
+    return find_group(parent);
+}
+function orig_save(e, attr, val) {
+    if (e.attributes["fg:orig_" + attr] != undefined) return;
+    if (e.attributes[attr] == undefined) return;
+    if (val == undefined) val = e.attributes[attr].value;
+    e.setAttribute("fg:orig_" + attr, val);
+}
+function orig_load(e, attr) {
+    if (e.attributes["fg:orig_"+attr] == undefined) return;
+    e.attributes[attr].value = e.attributes["fg:orig_" + attr].value;
+    e.removeAttribute("fg:orig_" + attr);
+}
+function g_to_text(e) {
+    var text = find_child(e, "title").firstChild.nodeValue;
+    return (text)
+}
+function g_to_func(e) {
+    var func = g_to_text(e);
+    // if there's any manipulation we want to do to the function
+    // name before it's searched, do it here before returning.
+    return (func);
+}
+function get_monospace_width(frames) {
+    // Given the id="frames" element, return the width of text characters if
+    // this is a monospace font, otherwise return 0.
+    text = find_child(frames.children[0], "text");
+    originalContent = text.textContent;
+    text.textContent = "!";
+    bangWidth = text.getComputedTextLength();
+    text.textContent = "W";
+    wWidth = text.getComputedTextLength();
+    text.textContent = originalContent;
+    if (bangWidth === wWidth) {
+        return bangWidth;
+    } else {
+        return 0;
+    }
+}
+function update_text_for_elements(elements) {
+    // In order to render quickly in the browser, you want to do one pass of
+    // reading attributes, and one pass of mutating attributes. See
+    // https://web.dev/avoid-large-complex-layouts-and-layout-thrashing/ for details.
+
+    // Fall back to inefficient calculation, if we're variable-width font.
+    // TODO This should be optimized somehow too.
+    if (known_font_width === 0) {
+        for (var i = 0; i < elements.length; i++) {
+            update_text(elements[i]);
+        }
+        return;
+    }
+
+    var textElemNewAttributes = [];
+    for (var i = 0; i < elements.length; i++) {
+        var e = elements[i];
+        var r = find_child(e, "rect");
+        var t = find_child(e, "text");
+        var w = parseFloat(r.attributes.width.value) * frames.attributes.width.value / 100 - 3;
+        var txt = find_child(e, "title").textContent.replace(/\([^(]*\)$/,"");
+        var newX = format_percent((parseFloat(r.attributes.x.value) + (100 * 3 / frames.attributes.width.value)));
+
+        // Smaller than this size won't fit anything
+        if (w < 2 * known_font_width) {
+            textElemNewAttributes.push([newX, ""]);
+            continue;
+        }
+
+        // Fit in full text width
+        if (txt.length * known_font_width < w) {
+            textElemNewAttributes.push([newX, txt]);
+            continue;
+        }
+
+        var substringLength = Math.floor(w / known_font_width) - 2;
+        if (truncate_text_right) {
+            // Truncate the right side of the text.
+            textElemNewAttributes.push([newX, txt.substring(0, substringLength) + ".."]);
+            continue;
+        } else {
+            // Truncate the left side of the text.
+            textElemNewAttributes.push([newX, ".." + txt.substring(txt.length - substringLength, txt.length)]);
+            continue;
+        }
+    }
+
+    console.assert(textElemNewAttributes.length === elements.length, "Resize failed, please file a bug at https://github.com/jonhoo/inferno/");
+
+    // Now that we know new textContent, set it all in one go so we don't refresh a bazillion times.
+    for (var i = 0; i < elements.length; i++) {
+        var e = elements[i];
+        var values = textElemNewAttributes[i];
+        var t = find_child(e, "text");
+        t.attributes.x.value = values[0];
+        t.textContent = values[1];
+    }
+}
+
+function update_text(e) {
+    var r = find_child(e, "rect");
+    var t = find_child(e, "text");
+    var w = parseFloat(r.attributes.width.value) * frames.attributes.width.value / 100 - 3;
+    var txt = find_child(e, "title").textContent.replace(/\([^(]*\)$/,"");
+    t.attributes.x.value = format_percent((parseFloat(r.attributes.x.value) + (100 * 3 / frames.attributes.width.value)));
+
+    // Smaller than this size won't fit anything
+    if (w < 2 * fontsize * fontwidth) {
+        t.textContent = "";
+        return;
+    }
+    t.textContent = txt;
+    // Fit in full text width
+    if (t.getComputedTextLength() < w)
+        return;
+    if (truncate_text_right) {
+        // Truncate the right side of the text.
+        for (var x = txt.length - 2; x > 0; x--) {
+            if (t.getSubStringLength(0, x + 2) <= w) {
+                t.textContent = txt.substring(0, x) + "..";
+                return;
+            }
+        }
+    } else {
+        // Truncate the left side of the text.
+        for (var x = 2; x < txt.length; x++) {
+            if (t.getSubStringLength(x - 2, txt.length) <= w) {
+                t.textContent = ".." + txt.substring(x, txt.length);
+                return;
+            }
+        }
+    }
+    t.textContent = "";
+}
+// zoom
+function zoom_reset(e) {
+    if (e.tagName == "rect") {
+        e.attributes.x.value = format_percent(100 * parseInt(e.attributes["fg:x"].value) / total_samples);
+        e.attributes.width.value = format_percent(100 * parseInt(e.attributes["fg:w"].value) / total_samples);
+    }
+    if (e.childNodes == undefined) return;
+    for(var i = 0, c = e.childNodes; i < c.length; i++) {
+        zoom_reset(c[i]);
+    }
+}
+function zoom_child(e, x, zoomed_width_samples) {
+    if (e.tagName == "text") {
+        var parent_x = parseFloat(find_child(e.parentNode, "rect[x]").attributes.x.value);
+        e.attributes.x.value = format_percent(parent_x + (100 * 3 / frames.attributes.width.value));
+    } else if (e.tagName == "rect") {
+        e.attributes.x.value = format_percent(100 * (parseInt(e.attributes["fg:x"].value) - x) / zoomed_width_samples);
+        e.attributes.width.value = format_percent(100 * parseInt(e.attributes["fg:w"].value) / zoomed_width_samples);
+    }
+    if (e.childNodes == undefined) return;
+    for(var i = 0, c = e.childNodes; i < c.length; i++) {
+        zoom_child(c[i], x, zoomed_width_samples);
+    }
+}
+function zoom_parent(e) {
+    if (e.attributes) {
+        if (e.attributes.x != undefined) {
+            e.attributes.x.value = "0.0%";
+        }
+        if (e.attributes.width != undefined) {
+            e.attributes.width.value = "100.0%";
+        }
+    }
+    if (e.childNodes == undefined) return;
+    for(var i = 0, c = e.childNodes; i < c.length; i++) {
+        zoom_parent(c[i]);
+    }
+}
+function zoom(node) {
+    var attr = find_child(node, "rect").attributes;
+    var width = parseInt(attr["fg:w"].value);
+    var xmin = parseInt(attr["fg:x"].value);
+    var xmax = xmin + width;
+    var ymin = parseFloat(attr.y.value);
+    unzoombtn.classList.remove("hide");
+    var el = frames.children;
+    var to_update_text = [];
+    for (var i = 0; i < el.length; i++) {
+        var e = el[i];
+        var a = find_child(e, "rect").attributes;
+        var ex = parseInt(a["fg:x"].value);
+        var ew = parseInt(a["fg:w"].value);
+        // Is it an ancestor
+        if (!inverted) {
+            var upstack = parseFloat(a.y.value) > ymin;
+        } else {
+            var upstack = parseFloat(a.y.value) < ymin;
+        }
+        if (upstack) {
+            // Direct ancestor
+            if (ex <= xmin && (ex+ew) >= xmax) {
+                e.classList.add("parent");
+                zoom_parent(e);
+                to_update_text.push(e);
+            }
+            // not in current path
+            else
+                e.classList.add("hide");
+        }
+        // Children maybe
+        else {
+            // no common path
+            if (ex < xmin || ex >= xmax) {
+                e.classList.add("hide");
+            }
+            else {
+                zoom_child(e, xmin, width);
+                to_update_text.push(e);
+            }
+        }
+    }
+    update_text_for_elements(to_update_text);
+}
+function unzoom() {
+    unzoombtn.classList.add("hide");
+    var el = frames.children;
+    for(var i = 0; i < el.length; i++) {
+        el[i].classList.remove("parent");
+        el[i].classList.remove("hide");
+        zoom_reset(el[i]);
+    }
+    update_text_for_elements(el);
+}
+// search
+function reset_search() {
+    var el = document.querySelectorAll("#frames rect");
+    for (var i = 0; i < el.length; i++) {
+        orig_load(el[i], "fill")
+    }
+    var params = get_params();
+    delete params.s;
+    history.replaceState(null, null, parse_params(params));
+}
+function search_prompt() {
+    if (!searching) {
+        var term = prompt("Enter a search term (regexp " +
+            "allowed, eg: ^ext4_)", "");
+        if (term != null) {
+            search(term)
+        }
+    } else {
+        reset_search();
+        searching = 0;
+        searchbtn.classList.remove("show");
+        searchbtn.firstChild.nodeValue = "Search"
+        matchedtxt.classList.add("hide");
+        matchedtxt.firstChild.nodeValue = ""
+    }
+}
+function search(term) {
+    var re = new RegExp(term);
+    var el = frames.children;
+    var matches = new Object();
+    var maxwidth = 0;
+    for (var i = 0; i < el.length; i++) {
+        var e = el[i];
+        // Skip over frames which are either not visible, or below the zoomed-to frame
+        if (e.classList.contains("hide") || e.classList.contains("parent")) {
+            continue;
+        }
+        var func = g_to_func(e);
+        var rect = find_child(e, "rect");
+        if (func == null || rect == null)
+            continue;
+        // Save max width. Only works as we have a root frame
+        var w = parseInt(rect.attributes["fg:w"].value);
+        if (w > maxwidth)
+            maxwidth = w;
+        if (func.match(re)) {
+            // highlight
+            var x = parseInt(rect.attributes["fg:x"].value);
+            orig_save(rect, "fill");
+            rect.attributes.fill.value = searchcolor;
+            // remember matches
+            if (matches[x] == undefined) {
+                matches[x] = w;
+            } else {
+                if (w > matches[x]) {
+                    // overwrite with parent
+                    matches[x] = w;
+                }
+            }
+            searching = 1;
+        }
+    }
+    if (!searching)
+        return;
+    var params = get_params();
+    params.s = term;
+    history.replaceState(null, null, parse_params(params));
+
+    searchbtn.classList.add("show");
+    searchbtn.firstChild.nodeValue = "Reset Search";
+    // calculate percent matched, excluding vertical overlap
+    var count = 0;
+    var lastx = -1;
+    var lastw = 0;
+    var keys = Array();
+    for (k in matches) {
+        if (matches.hasOwnProperty(k))
+            keys.push(k);
+    }
+    // sort the matched frames by their x location
+    // ascending, then width descending
+    keys.sort(function(a, b){
+        return a - b;
+    });
+    // Step through frames saving only the biggest bottom-up frames
+    // thanks to the sort order. This relies on the tree property
+    // where children are always smaller than their parents.
+    for (var k in keys) {
+        var x = parseInt(keys[k]);
+        var w = matches[keys[k]];
+        if (x >= lastx + lastw) {
+            count += w;
+            lastx = x;
+            lastw = w;
+        }
+    }
+    // display matched percent
+    matchedtxt.classList.remove("hide");
+    var pct = 100 * count / maxwidth;
+    if (pct != 100) pct = pct.toFixed(1);
+    matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%";
+}
+function format_percent(n) {
+    return n.toFixed(4) + "%";
+}
+]]></script><rect x="0" y="0" width="100%" height="310" fill="url(#background)"/><text id="title" fill="rgb(0,0,0)" x="50.0000%" y="24.00">Flame Graph</text><text id="details" fill="rgb(0,0,0)" x="10" y="293.00"> </text><text id="unzoom" class="hide" fill="rgb(0,0,0)" x="10" y="24.00">Reset Zoom</text><text id="search" fill="rgb(0,0,0)" x="1190" y="24.00">Search</text><text id="matched" fill="rgb(0,0,0)" x="1190" y="293.00"> </text><svg id="frames" x="10" width="1180" total_samples="27"><g><title>string-search-heaptrack`tutorials::string_search::core::Entries::search (3 samples, 11.11%)</title><rect x="0.0000%" y="165" width="11.1111%" height="15" fill="rgb(227,0,7)" fg:x="0" fg:w="3"/><text x="0.2500%" y="175.50">string-search-he..</text></g><g><title>string-search-heaptrack`tutorials::utils::generate::phrases (1 samples, 3.70%)</title><rect x="11.1111%" y="149" width="3.7037%" height="15" fill="rgb(217,0,24)" fg:x="3" fg:w="1"/><text x="11.3611%" y="159.50">stri..</text></g><g><title>string-search-heaptrack`core::iter::adapters::try_process (1 samples, 3.70%)</title><rect x="11.1111%" y="133" width="3.7037%" height="15" fill="rgb(221,193,54)" fg:x="3" fg:w="1"/><text x="11.3611%" y="143.50">stri..</text></g><g><title>string-search-heaptrack`&lt;alloc::vec::Vec&lt;T&gt; as alloc::vec::spec_from_iter::SpecFromIter&lt;T,I&gt;&gt;::from_iter (1 samples, 3.70%)</title><rect x="11.1111%" y="117" width="3.7037%" height="15" fill="rgb(248,212,6)" fg:x="3" fg:w="1"/><text x="11.3611%" y="127.50">stri..</text></g><g><title>string-search-heaptrack`&lt;core::iter::adapters::map::Map&lt;I,F&gt; as core::iter::traits::iterator::Iterator&gt;::try_fold (1 samples, 3.70%)</title><rect x="11.1111%" y="101" width="3.7037%" height="15" fill="rgb(208,68,35)" fg:x="3" fg:w="1"/><text x="11.3611%" y="111.50">stri..</text></g><g><title>string-search-heaptrack`&lt;alloc::vec::Vec&lt;T,A&gt; as alloc::vec::spec_extend::SpecExtend&lt;T,I&gt;&gt;::spec_extend (1 samples, 3.70%)</title><rect x="11.1111%" y="85" width="3.7037%" height="15" fill="rgb(232,128,0)" fg:x="3" fg:w="1"/><text x="11.3611%" y="95.50">stri..</text></g><g><title>string-search-heaptrack`rand::rngs::adapter::reseeding::ReseedingCore&lt;R,Rsdr&gt;::reseed_and_generate (1 samples, 3.70%)</title><rect x="11.1111%" y="69" width="3.7037%" height="15" fill="rgb(207,160,47)" fg:x="3" fg:w="1"/><text x="11.3611%" y="79.50">stri..</text></g><g><title>string-search-heaptrack`&lt;rand_core::os::OsRng as rand_core::RngCore&gt;::try_fill_bytes (1 samples, 3.70%)</title><rect x="11.1111%" y="53" width="3.7037%" height="15" fill="rgb(228,23,34)" fg:x="3" fg:w="1"/><text x="11.3611%" y="63.50">stri..</text></g><g><title>libsystem_kernel.dylib`getentropy (1 samples, 3.70%)</title><rect x="11.1111%" y="37" width="3.7037%" height="15" fill="rgb(218,30,26)" fg:x="3" fg:w="1"/><text x="11.3611%" y="47.50">libs..</text></g><g><title>string-search-heaptrack`core::hash::BuildHasher::hash_one (5 samples, 18.52%)</title><rect x="14.8148%" y="133" width="18.5185%" height="15" fill="rgb(220,122,19)" fg:x="4" fg:w="5"/><text x="15.0648%" y="143.50">string-search-heaptrack`core:..</text></g><g><title>string-search-heaptrack`&lt;core::hash::sip::Hasher&lt;S&gt; as core::hash::Hasher&gt;::write (3 samples, 11.11%)</title><rect x="33.3333%" y="133" width="11.1111%" height="15" fill="rgb(250,228,42)" fg:x="9" fg:w="3"/><text x="33.5833%" y="143.50">string-search-he..</text></g><g><title>string-search-heaptrack`tutorials::string_search::core::Entries::search (16 samples, 59.26%)</title><rect x="14.8148%" y="149" width="59.2593%" height="15" fill="rgb(240,193,28)" fg:x="4" fg:w="16"/><text x="15.0648%" y="159.50">string-search-heaptrack`tutorials::string_search::core::Entries::search</text></g><g><title>string-search-heaptrack`tutorials::string_search::core::Entries::add_many (1 samples, 3.70%)</title><rect x="74.0741%" y="149" width="3.7037%" height="15" fill="rgb(216,20,37)" fg:x="20" fg:w="1"/><text x="74.3241%" y="159.50">stri..</text></g><g><title>string-search-heaptrack`&lt;core::iter::adapters::map::Map&lt;I,F&gt; as core::iter::traits::iterator::Iterator&gt;::fold (1 samples, 3.70%)</title><rect x="74.0741%" y="133" width="3.7037%" height="15" fill="rgb(206,188,39)" fg:x="20" fg:w="1"/><text x="74.3241%" y="143.50">stri..</text></g><g><title>string-search-heaptrack`hashbrown::map::HashMap&lt;K,V,S,A&gt;::insert (1 samples, 3.70%)</title><rect x="74.0741%" y="117" width="3.7037%" height="15" fill="rgb(217,207,13)" fg:x="20" fg:w="1"/><text x="74.3241%" y="127.50">stri..</text></g><g><title>string-search-heaptrack`core::hash::BuildHasher::hash_one (1 samples, 3.70%)</title><rect x="74.0741%" y="101" width="3.7037%" height="15" fill="rgb(231,73,38)" fg:x="20" fg:w="1"/><text x="74.3241%" y="111.50">stri..</text></g><g><title>string-search-heaptrack`DYLD-STUB$$memcmp (2 samples, 7.41%)</title><rect x="77.7778%" y="149" width="7.4074%" height="15" fill="rgb(225,20,46)" fg:x="21" fg:w="2"/><text x="78.0278%" y="159.50">string-sea..</text></g><g><title>libsystem_platform.dylib`_platform_memcmp (2 samples, 7.41%)</title><rect x="85.1852%" y="149" width="7.4074%" height="15" fill="rgb(210,31,41)" fg:x="23" fg:w="2"/><text x="85.4352%" y="159.50">libsystem_..</text></g><g><title>string-search-heaptrack`string_search_heaptrack::main (23 samples, 85.19%)</title><rect x="11.1111%" y="165" width="85.1852%" height="15" fill="rgb(221,200,47)" fg:x="3" fg:w="23"/><text x="11.3611%" y="175.50">string-search-heaptrack`string_search_heaptrack::main</text></g><g><title>all (27 samples, 100%)</title><rect x="0.0000%" y="261" width="100.0000%" height="15" fill="rgb(226,26,5)" fg:x="0" fg:w="27"/><text x="0.2500%" y="271.50"></text></g><g><title>dyld`start (27 samples, 100.00%)</title><rect x="0.0000%" y="245" width="100.0000%" height="15" fill="rgb(249,33,26)" fg:x="0" fg:w="27"/><text x="0.2500%" y="255.50">dyld`start</text></g><g><title>string-search-heaptrack`main (27 samples, 100.00%)</title><rect x="0.0000%" y="229" width="100.0000%" height="15" fill="rgb(235,183,28)" fg:x="0" fg:w="27"/><text x="0.2500%" y="239.50">string-search-heaptrack`main</text></g><g><title>string-search-heaptrack`std::rt::lang_start_internal (27 samples, 100.00%)</title><rect x="0.0000%" y="213" width="100.0000%" height="15" fill="rgb(221,5,38)" fg:x="0" fg:w="27"/><text x="0.2500%" y="223.50">string-search-heaptrack`std::rt::lang_start_internal</text></g><g><title>string-search-heaptrack`std::rt::lang_start::_{{closure}} (27 samples, 100.00%)</title><rect x="0.0000%" y="197" width="100.0000%" height="15" fill="rgb(247,18,42)" fg:x="0" fg:w="27"/><text x="0.2500%" y="207.50">string-search-heaptrack`std::rt::lang_start::_{{closure}}</text></g><g><title>string-search-heaptrack`std::sys::backtrace::__rust_begin_short_backtrace (27 samples, 100.00%)</title><rect x="0.0000%" y="181" width="100.0000%" height="15" fill="rgb(241,131,45)" fg:x="0" fg:w="27"/><text x="0.2500%" y="191.50">string-search-heaptrack`std::sys::backtrace::__rust_begin_short_backtrace</text></g><g><title>libsystem_malloc.dylib`_free (1 samples, 3.70%)</title><rect x="96.2963%" y="165" width="3.7037%" height="15" fill="rgb(249,31,29)" fg:x="26" fg:w="1"/><text x="96.5463%" y="175.50">libs..</text></g></svg></svg>
\ No newline at end of file
diff --git a/examples/limit-reader/README.md b/examples/limit-reader/README.md
new file mode 100644
index 0000000..c09d204
--- /dev/null
+++ b/examples/limit-reader/README.md
@@ -0,0 +1,3 @@
+# limit-reader
+
+See [better-limit-reader](https://crates.io/crates/better-limit-reader)
\ No newline at end of file
diff --git a/examples/traits-dyn-generics/pluggable-storage/.gitignore b/examples/traits-dyn-generics/pluggable-storage/.gitignore
new file mode 100644
index 0000000..c41cc9e
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/.gitignore
@@ -0,0 +1 @@
+/target
\ No newline at end of file
diff --git a/examples/traits-dyn-generics/pluggable-storage/Cargo.toml b/examples/traits-dyn-generics/pluggable-storage/Cargo.toml
new file mode 100644
index 0000000..e0ea049
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "pluggable-storage"
+version = "0.1.0"
+authors = ["Michael de Silva <michael@cyberdynea.io"]
+edition = "2021"
+
+[[bin]]
+name = "disk-backend"
+path = "src/bin/disk-backend.rs"
+
+[dependencies]
+anyhow = "1.0.86"
+derive_builder = "0.20.1"
+tokio = { version = "1.40.0", features = ["full"] }
diff --git a/examples/traits-dyn-generics/pluggable-storage/rust-toolchain.toml b/examples/traits-dyn-generics/pluggable-storage/rust-toolchain.toml
new file mode 100644
index 0000000..66eee23
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "beta"
\ No newline at end of file
diff --git a/examples/traits-dyn-generics/pluggable-storage/src/backend.rs b/examples/traits-dyn-generics/pluggable-storage/src/backend.rs
new file mode 100644
index 0000000..93474b7
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/src/backend.rs
@@ -0,0 +1,10 @@
+use anyhow::Result;
+use std::fmt::Debug;
+use std::future::Future;
+
+pub(crate) mod disk;
+pub(crate) mod s3;
+
+pub trait Backend: Debug {
+    fn persist(&mut self, data: &[u8]) -> impl Future<Output = Result<()>> + Send;
+}
diff --git a/examples/traits-dyn-generics/pluggable-storage/src/backend/disk.rs b/examples/traits-dyn-generics/pluggable-storage/src/backend/disk.rs
new file mode 100644
index 0000000..9464327
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/src/backend/disk.rs
@@ -0,0 +1,86 @@
+use anyhow::{Context, Result};
+use std::fmt::Debug;
+use std::ops::{Deref, DerefMut};
+use std::path::PathBuf;
+
+use super::Backend;
+
+#[derive(Debug)]
+pub struct FileBackend {
+    path: PathBuf,
+}
+
+impl FileBackend {
+    fn new(s: &str) -> Self {
+        Self { path: s.into() }
+    }
+}
+
+pub trait FileBackendTrait {
+    fn new(s: &str) -> Self;
+}
+
+impl FileBackendTrait for FileBackend {
+    // NOTE: This is a provided method via the Trait `FileBackendTrait`
+    fn new(s: &str) -> Self {
+        // NOTE: this is an associated method on `FileBackend`
+        Self::new(s)
+    }
+}
+
+#[derive(Debug)]
+pub struct FileBackendBuilder<T>(T);
+
+// Deref on inner type.
+impl<T> Deref for FileBackendBuilder<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for FileBackendBuilder<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T> FileBackendBuilder<T>
+where
+    T: FileBackendTrait,
+{
+    pub fn new(path: &str) -> Self {
+        Self(T::new(path))
+    }
+
+    pub fn build(self) -> T {
+        self.0
+    }
+}
+
+impl Backend for FileBackend {
+    async fn persist(&mut self, data: &[u8]) -> Result<()> {
+        if let Err(err) = tokio::fs::write(&self.path, data).await {
+            return Err(err).with_context(|| format!("Failed to persist to {:?}", self.path));
+        }
+
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[should_panic]
+    #[tokio::test]
+    async fn panic_when_writing_to_missing_directory() {
+        let data = String::from("If my calculations are correct, when this baby hits eighty-eight miles per hour... you're gonna see some serious s**t.");
+        let backend_builder: FileBackendBuilder<FileBackend> =
+            FileBackendBuilder::new("./missing/output.json");
+        let backend = &mut backend_builder.build();
+
+        backend.persist(data.as_bytes()).await.unwrap();
+    }
+}
diff --git a/examples/traits-dyn-generics/pluggable-storage/src/backend/s3.rs b/examples/traits-dyn-generics/pluggable-storage/src/backend/s3.rs
new file mode 100644
index 0000000..dfca030
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/src/backend/s3.rs
@@ -0,0 +1,92 @@
+#[allow(unused_imports)]
+use anyhow::{Context, Result};
+use derive_builder::Builder;
+use std::fmt::Debug;
+use std::ops::{Deref, DerefMut};
+
+use super::Backend;
+
+#[derive(Default, Builder, Debug)]
+#[builder(setter(into))]
+pub struct S3Config {
+    bucket: String,
+    file_name: String,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct S3Backend {
+    config: S3Config,
+}
+
+impl S3Backend {
+    fn new(config: S3Config) -> Self {
+        Self { config }
+    }
+
+    pub fn bucket(&self) -> String {
+        self.config.bucket.to_string()
+    }
+
+    pub fn file_name(&self) -> String {
+        self.config.file_name.to_string()
+    }
+}
+
+pub trait S3BackendTrait {
+    fn new(config: S3Config) -> Self;
+}
+
+impl S3BackendTrait for S3Backend {
+    // NOTE: This is a provided method via the Trait `S3BackendTrait`
+    fn new(config: S3Config) -> Self {
+        // NOTE: this is an associated method on `S3Backend`
+        Self::new(config)
+    }
+}
+
+#[derive(Debug)]
+pub struct S3BackendBuilder<T>(T);
+
+// Example on implemeting Deref for an inner type.
+impl<T> Deref for S3BackendBuilder<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for S3BackendBuilder<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T> S3BackendBuilder<T>
+where
+    T: S3BackendTrait,
+{
+    pub fn new(config: S3Config) -> Self {
+        Self(T::new(config))
+    }
+
+    pub fn build(self) -> T {
+        self.0
+    }
+}
+
+impl Backend for S3Backend {
+    async fn persist(&mut self, data: &[u8]) -> Result<()> {
+        let bucket_name = &self.bucket();
+        let file_name = &self.file_name();
+
+        unimplemented!();
+
+        // if let Err(err) = _ {
+        //   return Err(err).with_context(|| format!("Failed to persist to {:?}", self.path));
+        // }
+
+        // Ok(())
+    }
+}
diff --git a/examples/traits-dyn-generics/pluggable-storage/src/bin/disk-backend.rs b/examples/traits-dyn-generics/pluggable-storage/src/bin/disk-backend.rs
new file mode 100644
index 0000000..7e9895e
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/src/bin/disk-backend.rs
@@ -0,0 +1,15 @@
+use pluggable_storage::prelude::*;
+
+extern crate pluggable_storage;
+
+#[tokio::main]
+async fn main() -> Result<()> {
+  // This will be replaced with a source of data using Serde
+  let data = String::default();
+  let backend_builder: FileBackendBuilder<FileBackend> = FileBackendBuilder::new("./output/output.json");
+  let backend = &mut backend_builder.build();
+
+  backend.persist(data.as_bytes()).await?;
+
+  Ok(())
+}
diff --git a/examples/traits-dyn-generics/pluggable-storage/src/bin/s3-backend.rs b/examples/traits-dyn-generics/pluggable-storage/src/bin/s3-backend.rs
new file mode 100644
index 0000000..b0dc6d2
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/src/bin/s3-backend.rs
@@ -0,0 +1,21 @@
+use pluggable_storage::prelude::*;
+
+extern crate pluggable_storage;
+
+#[tokio::main]
+async fn main() -> Result<()> {
+  // This will be replaced with a source of data using Serde
+  let data = String::default();
+
+  let config = S3ConfigBuilder::default()
+    // block
+    .bucket("pluggable_storage_demo")
+    .file_name("output.json")
+    .build()?;
+  let backend_builder: S3BackendBuilder<S3Backend> = S3BackendBuilder::new(config);
+  let backend = &mut backend_builder.build();
+
+  backend.persist(data.as_bytes()).await?;
+
+  Ok(())
+}
diff --git a/examples/traits-dyn-generics/pluggable-storage/src/lib.rs b/examples/traits-dyn-generics/pluggable-storage/src/lib.rs
new file mode 100644
index 0000000..9571154
--- /dev/null
+++ b/examples/traits-dyn-generics/pluggable-storage/src/lib.rs
@@ -0,0 +1,11 @@
+pub(crate) mod backend;
+
+/// Re-exports
+pub mod prelude {
+  pub use crate::backend::{
+    disk::{FileBackend, FileBackendBuilder},
+    s3::{S3Backend, S3BackendBuilder, S3Config, S3ConfigBuilder},
+    Backend,
+  };
+  pub use anyhow::{Context, Result};
+}
diff --git a/examples/traits-dyn-generics/trait-objects-downcast/Cargo.toml b/examples/traits-dyn-generics/trait-objects-downcast/Cargo.toml
new file mode 100644
index 0000000..c6567d6
--- /dev/null
+++ b/examples/traits-dyn-generics/trait-objects-downcast/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "trait-objects"
+version = "0.1.0"
+authors = ["Michael de Silva <michael@cyberdynea.io"]
+edition = "2021"
+
+[dependencies]
+rand = "0.7"
+downcast-rs = "1.2.1"
diff --git a/examples/traits-dyn-generics/trait-objects-downcast/scatch.rs b/examples/traits-dyn-generics/trait-objects-downcast/scatch.rs
new file mode 100644
index 0000000..4bb7e8b
--- /dev/null
+++ b/examples/traits-dyn-generics/trait-objects-downcast/scatch.rs
@@ -0,0 +1,38 @@
+fn log_any<T: Any + Debug>(value: &T) {
+    let value_any = value as &dyn Any;
+  
+    // Try to convert our value its concrete type
+    match value_any.downcast_ref::<String>() {
+      Some(as_string) => {
+        println!("String ({}): {}", as_string.len(), as_string);
+      }
+      None => {
+        println!("{value:?} is not a String");
+      }
+    }
+  
+    match value_any.downcast_ref::<i32>() {
+      Some(as_i32) => {
+        println!("i32: {}", as_i32);
+      }
+      None => {
+        println!("{value:?} is not an i32");
+      }
+    }
+  }
+  
+  pub mod box_deref {
+    use super::*;
+  
+    fn example() {
+      let boxed: Box<dyn Any> = Box::new(3_i32);
+      // You're more likely to want this:
+      let actual_id = (&*boxed).type_id();
+      // ... than this:
+      let boxed_id = boxed.type_id();
+  
+      assert_eq!(actual_id, TypeId::of::<i32>());
+      assert_eq!(boxed_id, TypeId::of::<Box<dyn Any>>());
+    }
+  }
+  
\ No newline at end of file
diff --git a/examples/traits-dyn-generics/trait-objects-downcast/src/main.rs b/examples/traits-dyn-generics/trait-objects-downcast/src/main.rs
new file mode 100644
index 0000000..55d287f
--- /dev/null
+++ b/examples/traits-dyn-generics/trait-objects-downcast/src/main.rs
@@ -0,0 +1,137 @@
+use downcast_rs::{impl_downcast, Downcast};
+use rand;
+use rand::seq::SliceRandom;
+use rand::Rng;
+use std::any::{Any, TypeId};
+use std::fmt::Debug;
+use std::fmt::Display;
+use std::ops::{Deref, DerefMut};
+
+#[derive(Debug)]
+struct Dwarf {}
+
+impl Display for Dwarf {
+  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    write!(f, "I may be small but the ladies don't complain!")
+  }
+}
+
+#[derive(Debug)]
+struct Elf {}
+
+#[derive(Debug)]
+struct Human {}
+
+#[derive(Debug)]
+enum Thing {
+  Sword,
+  Trinket,
+}
+
+trait Enchanter: std::fmt::Debug {
+  fn competency(&self) -> f64;
+
+  fn enchant(&self, thing: &mut Thing) {
+    let probability_of_success = self.competency();
+    let spell_is_successful = rand::thread_rng().gen_bool(probability_of_success); // <1>
+
+    print!("{:?} mutters incoherently. ", self);
+    if spell_is_successful {
+      println!("The {:?} glows brightly.", thing);
+    } else {
+      println!(
+        "The {:?} fizzes, \
+             then turns into a worthless trinket.",
+        thing
+      );
+      *thing = Thing::Trinket {};
+    }
+  }
+}
+
+impl Enchanter for Dwarf {
+  fn competency(&self) -> f64 {
+    0.5 // <2>
+  }
+}
+impl Enchanter for Elf {
+  fn competency(&self) -> f64 {
+    0.95 // <3>
+  }
+}
+impl Enchanter for Human {
+  fn competency(&self) -> f64 {
+    0.8 // <4>
+  }
+}
+
+/// Holds the log value, stored on the heap.
+#[derive(Debug)]
+struct LogRecord {
+  pub text: String,
+}
+
+impl LogRecord {
+  fn new() -> Self {
+    Self {
+      text: String::default(),
+    }
+  }
+}
+
+trait Recordable: std::fmt::Debug + Downcast {
+  fn set_text(&mut self, _: String) {}
+
+  fn text(&self) -> String;
+}
+impl_downcast!(Recordable);
+
+impl Recordable for LogRecord {
+  fn set_text(&mut self, value: String) {
+    self.text = value;
+  }
+
+  fn text(&self) -> String {
+    self.text.to_string()
+  }
+}
+
+// This is a pointless downcast, as the same can be achieved with generics.
+fn log_enchanted<'a, T: Any + Debug>(value: &T, l: &'a mut impl Recordable) -> &'a dyn Recordable {
+  let value_any = value as &dyn Any;
+
+  // Try to convert our value its concrete type
+  match value_any.downcast_ref::<Dwarf>() {
+    Some(_) => {
+      l.set_text("Default text within the recorder".to_string());
+
+      l
+    }
+    _ => l,
+  }
+}
+
+fn main() {
+  let mut it = Thing::Sword;
+
+  let d = Dwarf {};
+  let e = Elf {};
+  let h = Human {};
+
+  let party: Vec<&dyn Enchanter> = vec![&d, &h, &e]; // <5>
+
+  // This is a contrived example to try and downcase from a leaked Box, to its concrete type without breaking Safety.
+  let d = Dwarf {};
+  let mut l = LogRecord::new();
+  let r = log_enchanted(&d, &mut l);
+  assert_eq!("Default text within the recorder".to_string(), r.text());
+
+  match r.downcast_ref::<LogRecord>() {
+    Some(record) => println!("Record: {}", record.text),
+    None => println!("Downcast failed"),
+  }
+
+  let spellcaster = party.choose(&mut rand::thread_rng()).unwrap();
+
+  spellcaster.enchant(&mut it);
+}
diff --git a/examples/traits-dyn-generics/trait-objects-without-downcast-generics/Cargo.toml b/examples/traits-dyn-generics/trait-objects-without-downcast-generics/Cargo.toml
new file mode 100644
index 0000000..c6567d6
--- /dev/null
+++ b/examples/traits-dyn-generics/trait-objects-without-downcast-generics/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "trait-objects"
+version = "0.1.0"
+authors = ["Michael de Silva <michael@cyberdynea.io"]
+edition = "2021"
+
+[dependencies]
+rand = "0.7"
+downcast-rs = "1.2.1"
diff --git a/examples/traits-dyn-generics/trait-objects-without-downcast-generics/scatch.rs b/examples/traits-dyn-generics/trait-objects-without-downcast-generics/scatch.rs
new file mode 100644
index 0000000..4bb7e8b
--- /dev/null
+++ b/examples/traits-dyn-generics/trait-objects-without-downcast-generics/scatch.rs
@@ -0,0 +1,38 @@
+fn log_any<T: Any + Debug>(value: &T) {
+    let value_any = value as &dyn Any;
+  
+    // Try to convert our value its concrete type
+    match value_any.downcast_ref::<String>() {
+      Some(as_string) => {
+        println!("String ({}): {}", as_string.len(), as_string);
+      }
+      None => {
+        println!("{value:?} is not a String");
+      }
+    }
+  
+    match value_any.downcast_ref::<i32>() {
+      Some(as_i32) => {
+        println!("i32: {}", as_i32);
+      }
+      None => {
+        println!("{value:?} is not an i32");
+      }
+    }
+  }
+  
+  pub mod box_deref {
+    use super::*;
+  
+    fn example() {
+      let boxed: Box<dyn Any> = Box::new(3_i32);
+      // You're more likely to want this:
+      let actual_id = (&*boxed).type_id();
+      // ... than this:
+      let boxed_id = boxed.type_id();
+  
+      assert_eq!(actual_id, TypeId::of::<i32>());
+      assert_eq!(boxed_id, TypeId::of::<Box<dyn Any>>());
+    }
+  }
+  
\ No newline at end of file
diff --git a/examples/traits-dyn-generics/trait-objects-without-downcast-generics/src/main.rs b/examples/traits-dyn-generics/trait-objects-without-downcast-generics/src/main.rs
new file mode 100644
index 0000000..774d5ef
--- /dev/null
+++ b/examples/traits-dyn-generics/trait-objects-without-downcast-generics/src/main.rs
@@ -0,0 +1,130 @@
+use downcast_rs::{impl_downcast, Downcast};
+use rand;
+use rand::seq::SliceRandom;
+use rand::Rng;
+use std::any::{Any, TypeId};
+use std::fmt::Debug;
+use std::fmt::Display;
+use std::ops::{Deref, DerefMut};
+
+#[derive(Debug)]
+struct Dwarf {}
+
+impl Display for Dwarf {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "I may be small but the ladies don't complain!")
+    }
+}
+
+#[derive(Debug)]
+struct Elf {}
+
+#[derive(Debug)]
+struct Human {}
+
+#[derive(Debug)]
+enum Thing {
+    Sword,
+    Trinket,
+}
+
+trait Enchanter: std::fmt::Debug {
+    fn competency(&self) -> f64;
+
+    fn enchant(&self, thing: &mut Thing) {
+        let probability_of_success = self.competency();
+        let spell_is_successful = rand::thread_rng().gen_bool(probability_of_success); // <1>
+
+        print!("{:?} mutters incoherently. ", self);
+        if spell_is_successful {
+            println!("The {:?} glows brightly.", thing);
+        } else {
+            println!(
+                "The {:?} fizzes, \
+             then turns into a worthless trinket.",
+                thing
+            );
+            *thing = Thing::Trinket {};
+        }
+    }
+}
+
+impl Enchanter for Dwarf {
+    fn competency(&self) -> f64 {
+        0.5 // <2>
+    }
+}
+impl Enchanter for Elf {
+    fn competency(&self) -> f64 {
+        0.95 // <3>
+    }
+}
+impl Enchanter for Human {
+    fn competency(&self) -> f64 {
+        0.8 // <4>
+    }
+}
+
+/// Holds the log value, stored on the heap.
+#[derive(Debug)]
+struct LogRecord {
+    pub text: String,
+}
+
+impl LogRecord {
+    fn new() -> Self {
+        Self {
+            text: String::default(),
+        }
+    }
+}
+
+trait Recordable: Debug {
+    fn text(&self) -> String;
+
+    fn set_text(&mut self, _: String);
+}
+
+impl Recordable for LogRecord {
+    fn set_text(&mut self, value: String) {
+        self.text = value;
+    }
+
+    fn text(&self) -> String {
+        self.text.to_string()
+    }
+}
+
+fn log_enchanted<'a, T: Any + Debug, U: Recordable>(value: &T, l: &'a mut U) -> &'a U {
+    let value_any = value as &dyn Any;
+
+    // Try to convert our value its concrete type
+    match value_any.downcast_ref::<Dwarf>() {
+        Some(_) => {
+            l.set_text("Default text within the recorder".to_string());
+
+            l
+        }
+        _ => l,
+    }
+}
+
+fn main() {
+    let mut it = Thing::Sword;
+
+    let d = Dwarf {};
+    let e = Elf {};
+    let h = Human {};
+
+    let party: Vec<&dyn Enchanter> = vec![&d, &h, &e]; // <5>
+
+    // This is a contrived example to try and downcase from a leaked Box, to its concrete type without breaking Safety.
+    let d = Dwarf {};
+    let mut l = LogRecord::new();
+    let r: &LogRecord = log_enchanted(&d, &mut l);
+    assert_eq!("Default text within the recorder".to_string(), r.text());
+
+    let spellcaster = party.choose(&mut rand::thread_rng()).unwrap();
+
+    spellcaster.enchant(&mut it);
+}
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 0000000..271800c
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "nightly"
\ No newline at end of file
diff --git a/src/bin/async-1.rs b/src/bin/async-1.rs
new file mode 100644
index 0000000..8d31abe
--- /dev/null
+++ b/src/bin/async-1.rs
@@ -0,0 +1,34 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use std::pin::Pin;
+
+async fn blocks(item: Item) -> Result<(), Error> {
+    let my_string = "foo".to_string();
+
+    let future_one = async {
+        // ...
+        println!("{my_string}");
+    };
+
+    let future_two = async {
+        // ...
+        println!("{my_string}");
+    };
+
+    // Run both futures to completion, printing "foo" twice:
+    let ((), ()) = futures::join!(future_one, future_two);
+
+    Ok(())
+}
+
+struct Item {}
+
+#[tokio::main]
+async fn main() {
+    let item = Item {};
+    // let pinned = Box::pin(item);
+
+    let _ = blocks(item).await;
+}
diff --git a/src/bin/async-fut-reqwest.rs b/src/bin/async-fut-reqwest.rs
new file mode 100644
index 0000000..b85767a
--- /dev/null
+++ b/src/bin/async-fut-reqwest.rs
@@ -0,0 +1,106 @@
+use async_trait::async_trait;
+use backon::{ExponentialBuilder, Retryable};
+use bytes::Bytes;
+use helpers::with_retry;
+use reqwest::{Error, Response};
+use retry_strategy::RetryStrategy;
+use std::future::Future;
+
+// Newtype wrapper for reqwest::Client (async)
+#[derive(Default)]
+pub struct ReqwestClient(reqwest::Client);
+
+impl ReqwestClient {
+    pub fn new() -> Self {
+        Self(reqwest::Client::new())
+    }
+
+    pub fn client(&self) -> &reqwest::Client {
+        &self.0
+    }
+
+    pub fn client_mut(&mut self) -> &mut reqwest::Client {
+        &mut self.0
+    }
+}
+
+// Trait for the HTTP client
+#[async_trait]
+pub trait HttpClient {
+    async fn post(&self, url: &str, api_key: &str, body: &[u8]) -> Result<Response, Error>;
+}
+
+// Implement HttpClient for the newtype with exponential backoff
+#[async_trait]
+#[allow(clippy::redundant_closure)]
+impl HttpClient for ReqwestClient {
+    // Alternatively, we could also pass `body: Bytes` and inside the async closure use `body.clone()`, as this is what reqwest expects.
+    async fn post(&self, url: &str, api_key: &str, body: &[u8]) -> Result<Response, Error> {
+        let retry_strategy = RetryStrategy::default().get_config();
+
+        let operation = async || {
+            let body = Bytes::copy_from_slice(body);
+
+            self.client()
+                .post(url)
+                .header("Authorization", format!("Bearer {}", api_key))
+                .header("Content-Type", "application/json")
+                .body(body)
+                .send()
+                .await
+        };
+
+        // Perform retry operation
+        with_retry(operation, retry_strategy).await
+    }
+}
+
+mod helpers {
+    use super::*;
+
+    /// Perform the retry operation with the given closure and retry strategy
+    pub async fn with_retry<F, Fut>(
+        closure: F,
+        retry_strategy: ExponentialBuilder,
+    ) -> Result<Response, Error>
+    where
+        F: Fn() -> Fut,
+        Fut: Future<Output = Result<Response, Error>>,
+    {
+        let resp: Result<Response, Error> = closure.retry(retry_strategy).await;
+
+        // TODO: add error handling
+
+        resp
+    }
+}
+
+mod retry_strategy {
+    use backon::ExponentialBuilder;
+
+    const MAX_DELAY_MILLIS: u64 = 1000;
+    pub struct RetryStrategy(ExponentialBuilder);
+
+    impl Default for RetryStrategy {
+        /// Default backoff strategy. This uses defaults with jitter.
+        fn default() -> Self {
+            let retry_strategy = ExponentialBuilder::default()
+                .with_factor(2_f32)
+                .with_max_times(3)
+                .with_max_delay(std::time::Duration::from_millis(MAX_DELAY_MILLIS))
+                .with_jitter();
+
+            Self(retry_strategy)
+        }
+    }
+
+    impl RetryStrategy {
+        /// Get the backoff configuration.
+        pub fn get_config(self) -> ExponentialBuilder {
+            self.0
+        }
+    }
+}
+
+#[tokio::main]
+async fn main() {}
diff --git a/src/bin/common-backend.rs b/src/bin/common-backend.rs
new file mode 100644
index 0000000..3081d2e
--- /dev/null
+++ b/src/bin/common-backend.rs
@@ -0,0 +1,90 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use async_trait::async_trait;
+use std::fmt::Debug;
+use std::io::Write;
+use tokio::io::AsyncWriteExt;
+
+#[async_trait]
+pub trait PersistantBackend: Debug {
+    async fn insert(&mut self, data: Vec<u8>) -> Result<(), Error>;
+}
+
+pub mod backend {
+    use super::*;
+    use tokio::fs::File;
+
+    #[derive(Debug)]
+    pub struct FileStore {}
+
+    #[async_trait]
+    impl PersistantBackend for FileStore {
+        async fn insert(&mut self, data: Vec<u8>) -> Result<(), Error> {
+            let mut file = File::create("data.txt").await?;
+            let text = data
+                .iter()
+                .map(|b| b.to_string())
+                .collect::<Vec<String>>()
+                .join(",");
+
+            file.write_all(text.as_bytes()).await?;
+            Ok(())
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct PersistableBackend {
+    backend: Box<dyn PersistantBackend>,
+}
+
+#[tokio::main]
+async fn main() {
+    todo!()
+}
+
+pub async fn insert_data(backend: &mut PersistableBackend, data: Vec<u8>) -> Result<(), Error> {
+    backend.backend.insert(data).await
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use nom::AsBytes;
+    use tokio::fs::File;
+    use tokio::io::AsyncReadExt;
+
+    #[tokio::test]
+    async fn test_insert_data() {
+        let file_store = backend::FileStore {};
+        let mut backend = PersistableBackend {
+            backend: Box::new(file_store),
+        };
+
+        let data = vec![1, 2, 3];
+        insert_data(&mut backend, data.clone())
+            .await
+            .expect("Failed to insert data");
+
+        let mut file = File::open("data.txt").await.expect("Failed to open file");
+        let mut buffer = Vec::new();
+        file.read_to_end(&mut buffer)
+            .await
+            .expect("Failed to read file");
+
+        let text = data
+            .iter()
+            .map(|b| b.to_string())
+            .collect::<Vec<String>>()
+            .join(",");
+
+        assert_eq!(text.as_bytes(), buffer);
+
+        // Cleanup
+        tokio::fs::remove_file("data.txt")
+            .await
+            .expect("Failed to remove file");
+    }
+}
diff --git a/src/bin/db-abstraction1.rs b/src/bin/db-abstraction1.rs
new file mode 100644
index 0000000..9022454
--- /dev/null
+++ b/src/bin/db-abstraction1.rs
@@ -0,0 +1,85 @@
+#![allow(unused_variables)]
+
+use anyhow::Error;
+use std::future::Future;
+
+#[derive(Clone)]
+pub struct PostgresDatabase {
+    ignored_users_repository: PostgresIgnoredUsersRepository,
+}
+
+#[derive(Clone)]
+struct PostgresIgnoredUsersRepository {
+    pool: (),
+}
+
+pub struct IgnoredUser;
+
+#[derive(Debug, thiserror::Error)]
+pub enum IgnoredUsersRepositoryError {
+    #[error(transparent)]
+    Unknown(#[from] anyhow::Error),
+}
+
+pub trait IgnoredUsersRepository: Send + Sync {
+    fn create(
+        &self,
+        ignored_user_create: IgnoredUser,
+    ) -> impl Future<Output = Result<(), IgnoredUsersRepositoryError>> + Send;
+}
+
+pub struct Dependencies<'a, R> {
+    pub repository: &'a R,
+}
+
+pub struct Request;
+pub struct Response;
+
+pub struct AddIgnoredUser<'a, R> {
+    repository: &'a R,
+}
+
+impl<'a, R> AddIgnoredUser<'a, R>
+where
+    R: IgnoredUsersRepository,
+{
+    pub fn new(dependencies: Dependencies<'a, R>) -> Self {
+        Self {
+            repository: dependencies.repository,
+        }
+    }
+
+    pub async fn exec(&self, request: Request) -> Result<Response, Error> {
+        // NOTE: this call works because the type of `self.repository` is `&R` and `R` implements `IgnoredUsersRepository`
+        IgnoredUsersRepository::create(self.repository, IgnoredUser {}).await?;
+
+        Ok(Response)
+    }
+}
+
+impl IgnoredUsersRepository for PostgresIgnoredUsersRepository {
+    async fn create(
+        &self,
+        ignored_user_create: IgnoredUser,
+    ) -> Result<(), IgnoredUsersRepositoryError> {
+        // Perform the actual database operation here
+        println!("Creating ignored user");
+
+        Ok(())
+    }
+}
+
+#[tokio::main]
+pub async fn main() -> Result<(), Error> {
+    let repository = PostgresIgnoredUsersRepository { pool: () };
+
+    // This abstracts the use case from the DB operations that run on the repository
+    let use_case = AddIgnoredUser::new(Dependencies {
+        repository: &repository,
+    });
+
+    use_case.exec(Request {}).await?;
+    println!("Performed use case");
+
+    Ok(())
+}
diff --git a/src/bin/maybeuninit.rs b/src/bin/maybeuninit.rs
new file mode 100644
index 0000000..1466566
--- /dev/null
+++ b/src/bin/maybeuninit.rs
@@ -0,0 +1,56 @@
+#![feature(maybe_uninit_write_slice)]
+#![feature(maybe_uninit_slice)]
+
+use anyhow::Error;
+
+extern crate tutorials;
+
+pub fn main() -> Result<(), Error> {
+    Ok(())
+}
+
+pub(crate) mod mem {
+    use std::fmt;
+    use std::mem::MaybeUninit;
+    use std::str;
+
+    /// Used for slow path in `Display` implementations when alignment is required.
+    pub struct DisplayBuffer<const SIZE: usize> {
+        buf: [MaybeUninit<u8>; SIZE],
+        len: usize,
+    }
+
+    impl<const SIZE: usize> DisplayBuffer<SIZE> {
+        #[inline]
+        pub const fn new() -> Self {
+            Self {
+                buf: [MaybeUninit::uninit(); SIZE],
+                len: 0,
+            }
+        }
+
+        #[inline]
+        pub fn as_str(&self) -> &str {
+            // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation
+            // which writes a valid UTF-8 string to `buf` and correctly sets `len`.
+            unsafe {
+                let s = MaybeUninit::slice_assume_init_ref(&self.buf[..self.len]);
+                str::from_utf8_unchecked(s)
+            }
+        }
+    }
+
+    impl<const SIZE: usize> fmt::Write for DisplayBuffer<SIZE> {
+        fn write_str(&mut self, s: &str) -> fmt::Result {
+            let bytes = s.as_bytes();
+
+            if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) {
+                MaybeUninit::copy_from_slice(buf, bytes);
+                self.len += bytes.len();
+                Ok(())
+            } else {
+                Err(fmt::Error)
+            }
+        }
+    }
+}
diff --git a/src/bin/newtype-axum-1.rs b/src/bin/newtype-axum-1.rs
new file mode 100644
index 0000000..acc41f3
--- /dev/null
+++ b/src/bin/newtype-axum-1.rs
@@ -0,0 +1,59 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use hyper::header::HeaderValue;
+use std::fmt;
+use std::ops;
+use tower_http_0_2_4::cors::{CorsLayer, Origin};
+
+struct CorsOrigins<'a>(pub(crate) &'a Vec<String>);
+
+impl IntoIterator for CorsOrigins<'_> {
+    type Item = HeaderValue;
+    type IntoIter = std::vec::IntoIter<Self::Item>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        let mut collection: Vec<HeaderValue> = vec![];
+        let _result: Vec<String> = self
+            .0
+            .iter()
+            .map(|x| {
+                collection.push(HeaderValue::from_str(x).unwrap());
+                x.to_string()
+            })
+            .collect();
+
+        collection.into_iter()
+    }
+}
+
+impl<'a> fmt::Display for CorsOrigins<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.iter().fold(Ok(()), |result, origin| {
+            result.and_then(|_| writeln!(f, "{}", origin))
+        })
+    }
+}
+
+impl ops::Deref for CorsOrigins<'_> {
+    type Target = Vec<String>;
+
+    fn deref(&self) -> &Self::Target {
+        self.0
+    }
+}
+
+#[tokio::main]
+async fn main() {
+    let production_origins = vec!["https://example.com".parse().unwrap()];
+
+    tracing::info!(
+        "[ OK ]: CORS access enabled! {}",
+        CorsOrigins(&production_origins)
+    );
+
+    // In this example we create a Newtype to implement `IntoIterator`.  This is because Axum's `Origin::list()` function takes a generic parameter with a trait bound of `IntoIterator<Item = HeaderValue>`.
+    // We therefore implement the `IntoIterator` trait on our Newtype so that it can be passed as an argument to the `Origin::list()` function.
+    CorsLayer::new().allow_origin(Origin::list(CorsOrigins(&production_origins)));
+}
diff --git a/src/bin/nom-parse-hex-1.rs b/src/bin/nom-parse-hex-1.rs
new file mode 100644
index 0000000..c178bc4
--- /dev/null
+++ b/src/bin/nom-parse-hex-1.rs
@@ -0,0 +1,113 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+
+pub fn main() -> Result<(), Error> {
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests_3 {
+    use nom::{
+        bytes::complete::{tag, take_while_m_n},
+        combinator::map_res,
+        error::{context, convert_error},
+        sequence::Tuple,
+        IResult, Parser,
+    };
+
+    pub fn parse_hex_seg(input: &str) -> IResult<&str, u8, nom::error::VerboseError<&str>> {
+        let parse_two_hex_digits_parser_fn = take_while_m_n(
+            // RA block
+            2,
+            2,
+            |it: char| it.is_ascii_hexdigit(),
+        );
+
+        let mut map_res_fn = map_res(
+            // RA block
+            parse_two_hex_digits_parser_fn,
+            |it| u8::from_str_radix(it, 16),
+        );
+
+        map_res_fn.parse(input)
+    }
+
+    /// `nom` is used to parse the hex digits from string. Then [u8::from_str_radix] is
+    /// used to convert the hex string into a number. This can't fail, even though in the
+    /// function signature, that may return a [core::num::ParseIntError], which never
+    /// happens. Note the use of [nom::error::VerboseError] to get more detailed error
+    /// messages that are passed to [nom::error::convert_error].
+    ///
+    /// Even if [core::num::ParseIntError] were to be thrown, it would be consumed, and
+    /// a higher level `nom` error would be returned for the `map_res` combinator.
+    pub fn parse_hex_seg_combined(
+        input: &str,
+    ) -> IResult<&str, u8, nom::error::VerboseError<&str>> {
+        map_res(
+            take_while_m_n(2, 2, |it: char| it.is_ascii_hexdigit()),
+            |it| u8::from_str_radix(it, 16),
+        )
+        .parse(input)
+    }
+
+    /// Note the use of [nom::error::VerboseError] to get more detailed error messages
+    /// that are passed to [nom::error::convert_error].
+    pub fn root(input: &str) -> IResult<&str, (u8, u8, u8), nom::error::VerboseError<&str>> {
+        let (remainder, (_, red, green, blue)) = (
+            context("start of hex color", tag("#")),
+            context("hex seg 1", parse_hex_seg),
+            context("hex seg 2", parse_hex_seg),
+            context("hex seg 3", parse_hex_seg),
+        )
+            .parse(input)?;
+
+        Ok((remainder, (red, green, blue)))
+    }
+
+    #[test]
+    fn test_root_1() {
+        let input = "x#FF0000";
+        let result = root(input);
+        println!("{:?}", result);
+        assert!(result.is_err());
+
+        match result {
+            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
+                println!("Could not parse because ... {}", convert_error(input, e));
+            }
+            _ => { /* do nothing for nom::Err::Incomplete(_) */ }
+        }
+    }
+
+    #[test]
+    fn test_root_2() {
+        let input = "#FF_0000";
+        let result = root(input);
+        println!("{:?}", result);
+        assert!(result.is_err());
+
+        match result {
+            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
+                println!("Could not parse because ... {}", convert_error(input, e));
+            }
+            _ => { /* do nothing for nom::Err::Incomplete(_) */ }
+        }
+    }
+
+    #[test]
+    fn test_root_3() {
+        let input = "#FF00AA";
+        let result = root(input);
+        println!("{:?}", result);
+        assert!(result.is_ok());
+
+        match result {
+            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
+                println!("Could not parse because ... {}", convert_error(input, e));
+            }
+            _ => { /* do nothing for nom::Err::Incomplete(_) */ }
+        }
+    }
+}
diff --git a/src/bin/phrases-randomized.rs b/src/bin/phrases-randomized.rs
new file mode 100644
index 0000000..f67e08f
--- /dev/null
+++ b/src/bin/phrases-randomized.rs
@@ -0,0 +1,29 @@
+use crate::tutorials::string_search::core::*;
+use anyhow::Error;
+use rand::{thread_rng, Rng};
+use std::collections::HashMap;
+use std::hint::black_box;
+use tutorials::utils::generate::phrases_randomized;
+
+extern crate tutorials;
+
+pub fn main() -> Result<(), Error> {
+    static PHRASE_COUNT: i32 = 20;
+    // static INVOCATION_COUNT: i32 = 1_000;
+
+    let rng_phrases = phrases_randomized(PHRASE_COUNT.try_into()?, 3);
+    if let Ok(phrases) = rng_phrases {
+        // for _loop_idx in 0..INVOCATION_COUNT {
+        //     let _ = black_box(());
+        // }
+
+        let phrase_text = phrases
+            .iter()
+            .map(|el| format!("\"{}\", ", el))
+            .collect::<String>();
+        // dbg!(&phrase_text);
+        println!("Phrases generated [{}]: {}", &phrases.len(), &phrase_text);
+    }
+
+    Ok(())
+}
diff --git a/src/bin/pin-2.rs b/src/bin/pin-2.rs
new file mode 100644
index 0000000..1693efa
--- /dev/null
+++ b/src/bin/pin-2.rs
@@ -0,0 +1,53 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+
+#[derive(Debug)]
+struct Test {
+    a: String,
+    b: *const String,
+}
+
+impl Test {
+    fn new(txt: &str) -> Self {
+        Test {
+            a: String::from(txt),
+            b: std::ptr::null(),
+        }
+    }
+
+    fn init(&mut self) {
+        let self_ref: *const String = &self.a;
+        self.b = self_ref;
+    }
+
+    fn a(&self) -> &str {
+        &self.a
+    }
+
+    fn b(&self) -> &String {
+        assert!(
+            !self.b.is_null(),
+            "Test::b called without Test::init being called first"
+        );
+        unsafe { &*(self.b) }
+    }
+}
+
+// https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-detail
+// Demonstrates the issue of self-referential types without the use of pinning leading to UB.
+pub fn main() -> Result<(), Error> {
+    let mut test1 = Test::new("test1");
+    test1.init();
+    let mut test2 = Test::new("test2");
+    test2.init();
+
+    println!("a: {}, b: {}", test1.a(), test1.b());
+    std::mem::swap(&mut test1, &mut test2);
+    test1.a = "I've totally changed now!".to_string();
+
+    println!("a: {}, b: {}", test2.a(), test2.b());
+
+    Ok(())
+}
diff --git a/src/bin/pin-async-to-heap.rs b/src/bin/pin-async-to-heap.rs
new file mode 100644
index 0000000..f1abf20
--- /dev/null
+++ b/src/bin/pin-async-to-heap.rs
@@ -0,0 +1,47 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use pin_project;
+use std::marker::PhantomPinned;
+use std::pin::Pin;
+use std::ptr;
+
+#[derive(Debug)]
+struct Test {
+    a: String,
+    b: *const String,
+    _marker: PhantomPinned,
+}
+
+impl Test {
+    fn new(txt: &str) -> Pin<Box<Self>> {
+        let t = Test {
+            a: String::from(txt),
+            b: std::ptr::null(),
+            _marker: PhantomPinned,
+        };
+        let mut boxed = Box::pin(t);
+        let self_ptr: *const String = &boxed.a;
+        unsafe { boxed.as_mut().get_unchecked_mut().b = self_ptr };
+
+        boxed
+    }
+
+    fn a(self: Pin<&Self>) -> &str {
+        &self.get_ref().a
+    }
+
+    fn b(self: Pin<&Self>) -> &String {
+        unsafe { &*(self.b) }
+    }
+}
+
+#[tokio::main]
+pub async fn main() {
+    let test1 = Test::new("test1");
+    let test2 = Test::new("test2");
+
+    println!("a: {}, b: {}", test1.as_ref().a(), test1.as_ref().b());
+    println!("a: {}, b: {}", test2.as_ref().a(), test2.as_ref().b());
+}
diff --git a/src/bin/pin-nested-future.rs b/src/bin/pin-nested-future.rs
new file mode 100644
index 0000000..121c128
--- /dev/null
+++ b/src/bin/pin-nested-future.rs
@@ -0,0 +1,73 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use pin_project;
+
+use std::{
+    future::Future,
+    pin::Pin,
+    task::{Context, Poll},
+    time::{Duration, Instant},
+};
+
+#[pin_project::pin_project]
+pub struct TimedWrapper<Fut: Future> {
+    start: Option<Instant>,
+    #[pin]
+    future: Fut,
+}
+
+impl<Fut: Future> TimedWrapper<Fut> {
+    pub fn new(future: Fut) -> Self {
+        Self {
+            future,
+            start: None,
+        }
+    }
+}
+
+impl<Fut: Future> Future for TimedWrapper<Fut> {
+    type Output = (Fut::Output, Duration);
+
+    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+        let mut this = self.project();
+        // Call the inner poll, measuring how long it took.
+        let start = this.start.get_or_insert_with(Instant::now);
+        let inner_poll = this.future.as_mut().poll(cx);
+        let elapsed = start.elapsed();
+
+        match inner_poll {
+            // The inner future needs more time, so this future needs more time too
+            Poll::Pending => Poll::Pending,
+            // Success!
+            Poll::Ready(output) => Poll::Ready((output, elapsed)),
+        }
+    }
+}
+
+// Article: https://blog.cloudflare.com/pin-and-unpin-in-rust/
+// Github: https://github.com/adamchalmers/nested-future-example/blob/master/src/main.rs
+#[tokio::main]
+async fn main() {
+    let (resp, time) = TimedWrapper::new(fake_reqwest()).await;
+    println!(
+        "Got a HTTP {} in {}ms",
+        resp.unwrap().status(),
+        time.as_millis()
+    )
+}
+
+// Stubbing out use of `reqwest` with a dummy, just to get this to compile.
+struct FakeRequest {}
+
+impl FakeRequest {
+    fn status(&self) -> String {
+        String::from("")
+    }
+}
+async fn fake_reqwest() -> Result<FakeRequest, Error> {
+    let f = FakeRequest {};
+
+    Ok(f)
+}
diff --git a/src/bin/pin-project.rs b/src/bin/pin-project.rs
new file mode 100644
index 0000000..56a4873
--- /dev/null
+++ b/src/bin/pin-project.rs
@@ -0,0 +1,92 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use pin_project::pin_project;
+use std::marker::PhantomPinned;
+use std::pin::Pin;
+use std::ptr;
+
+#[derive(Default)]
+struct BagOfApples {
+    _require_pin: std::marker::PhantomPinned,
+}
+
+impl BagOfApples {
+    fn sell_one(self: Pin<&mut Self>) {
+        println!("Sold an apple!");
+    }
+}
+
+#[derive(Default)]
+struct BagOfOranges {
+    _require_pin: std::marker::PhantomPinned,
+}
+
+impl BagOfOranges {
+    fn sell_one(self: Pin<&mut Self>) {
+        println!("Sold an orange!");
+    }
+}
+
+#[derive(Default)]
+struct BagOfBananas {
+    _require_pin: std::marker::PhantomPinned,
+}
+
+impl BagOfBananas {
+    fn sell_one(self: Pin<&mut Self>) {
+        println!("Sold a banana!");
+    }
+}
+
+// ### Projected variant.
+#[pin_project]
+struct FruitStand {
+    #[pin]
+    apples: BagOfApples,
+    #[pin]
+    oranges: BagOfOranges,
+    #[pin]
+    bananas: BagOfBananas,
+
+    total_sold: usize,
+}
+
+impl FruitStand {
+    fn sell_one_of_each(mut self: Pin<&mut Self>) {
+        let self_projected = self.as_mut().project();
+
+        self_projected.apples.sell_one();
+        self_projected.oranges.sell_one();
+        self_projected.bananas.sell_one();
+        *self_projected.total_sold += 3;
+    }
+
+    fn new() -> Pin<Box<Self>> {
+        let this = Self {
+            apples: BagOfApples {
+                _require_pin: std::marker::PhantomPinned,
+            },
+            oranges: BagOfOranges {
+                _require_pin: std::marker::PhantomPinned,
+            },
+            bananas: BagOfBananas {
+                _require_pin: std::marker::PhantomPinned,
+            },
+            total_sold: 0,
+        };
+
+        Box::pin(this)
+    }
+}
+
+// `pin_project` on struct fields
+// Article: https://sander.saares.eu/2024/11/06/why-is-stdpinpin-so-weird/
+// Github: https://github.com/sandersaares/pins-in-rust/blob/main/examples/05_project.rs
+#[tokio::main]
+pub async fn main() {
+    let money_jar = &mut FruitStand::new();
+
+    money_jar.as_mut().sell_one_of_each();
+}
diff --git a/src/bin/pin-weird-1.rs b/src/bin/pin-weird-1.rs
new file mode 100644
index 0000000..c48857d
--- /dev/null
+++ b/src/bin/pin-weird-1.rs
@@ -0,0 +1,67 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use std::fmt::Debug;
+use std::pin::Pin;
+use std::ptr;
+
+extern crate tutorials;
+
+// NOTE: Warning: avoid the pin! macro unless you have a very good understanding of what it does. This macro is sometimes over-eagerly suggested by the compiler as the “solution” to pinning-related errors (as you may already have noticed in the compiler error listed in the previous chapter). However, this macro is only applicable under specific conditions and often not the right tool for the job.
+// https://sander.saares.eu/2024/11/06/why-is-stdpinpin-so-weird/
+
+pub struct BagOfApples {
+    count: usize,
+
+    // In the example code, this self-reference is mostly useless.
+    // This is just to keep the example code simple – the emphasis is
+    // on the effects of pinning, not why a type may be designed to need it.
+    self_reference: *mut BagOfApples,
+
+    _require_pin: std::marker::PhantomPinned,
+}
+
+impl BagOfApples {
+    pub fn new() -> Self {
+        BagOfApples {
+            count: 0,
+            // We cannot set this here because we have not yet
+            // created the BagOfApples – there is nothing to reference.
+            self_reference: ptr::null_mut(),
+            _require_pin: std::marker::PhantomPinned,
+        }
+    }
+
+    /// Call this after creating a BagOfApples to initialize the instance.
+    pub fn initialize(mut self: Pin<&mut Self>) {
+        // SAFETY: BagOfApples requires pinning and we do not allow
+        // the obtained pointer to be exposed outside this type, so
+        // we know it always points to a valid value and therefore it
+        // is safe to store the pointer. We have also reviewed the code of
+        // this function to ensure that we do not move the BagOfApples
+        // instance via the reference we obtain from here nor via the pointer.
+        let self_mut = unsafe { self.as_mut().get_unchecked_mut() };
+
+        self_mut.self_reference = self_mut;
+    }
+
+    pub fn count(&self) -> usize {
+        assert!(
+            !self.self_reference.is_null(),
+            "BagOfApples is not initialized"
+        );
+
+        // SAFETY: Simple read-only access to the count field, which
+        // is safe. We do it via the pointer for example purposes.
+        unsafe { (*self.self_reference).count }
+    }
+}
+
+pub fn main() -> Result<(), Error> {
+    let mut bag = Box::pin(BagOfApples::new());
+    bag.as_mut().initialize();
+    println!("Apple count: {}", bag.count());
+
+    Ok(())
+}
diff --git a/src/bin/pointers-1.rs b/src/bin/pointers-1.rs
new file mode 100644
index 0000000..a7d5b21
--- /dev/null
+++ b/src/bin/pointers-1.rs
@@ -0,0 +1,52 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use std::fmt::Debug;
+
+use anyhow::Error;
+
+extern crate tutorials;
+
+pub fn main() -> Result<(), Error> {
+    // Set the RUST_LOG, if it hasn't been explicitly defined
+    if std::env::var_os("RUST_LOG").is_none() {
+        std::env::set_var(
+            "RUST_LOG",
+            "tutorials=info,tower_http=trace,tokio=trace,runtime=trace",
+        )
+    }
+    tracing_subscriber::fmt()
+        .with_max_level(tracing::Level::INFO)
+        .with_file(true)
+        .with_line_number(true)
+        .init();
+
+    let data = Box::new(0);
+    let data_ptr = data.as_ref() as *const i32;
+    tracing::info!(
+        "Address of the Boxed object on the heap represented by data_ptr: {:p} / {:?}",
+        data_ptr,
+        data
+    );
+
+    let box_deref = unsafe { *data_ptr };
+    tracing::info!(
+        "We can defreference the pointer to the Boxed object on the heap: {:?}",
+        box_deref
+    );
+
+    // Example with a String object
+    let str_point_memory = String::from("Text on the Heap");
+    let str_ref = &str_point_memory;
+    tracing::info!(
+        "Address of the object on the heap represented by str_point_memory: {:p}",
+        str_point_memory.as_ptr(),
+    );
+    tracing::info!(
+        "Address of str_point_memory on the stack {:p} / {:?}",
+        str_ref,
+        str_ref
+    );
+
+    Ok(())
+}
diff --git a/src/bin/sized-1.rs b/src/bin/sized-1.rs
new file mode 100644
index 0000000..21d3eae
--- /dev/null
+++ b/src/bin/sized-1.rs
@@ -0,0 +1,108 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use std::fmt::Debug;
+
+use anyhow::Error;
+
+extern crate tutorials;
+
+pub trait Storable: Debug {
+    fn can_return_string(&self) -> String {
+        let caller_type = std::any::type_name::<Self>();
+
+        format!("Hello, this text is on the heap! {}", caller_type)
+    }
+
+    fn need_sized(self) -> Self
+    where
+        Self: Sized,
+    {
+        self
+    }
+}
+
+#[derive(Debug)]
+struct Holder<'a>(&'a dyn Storable);
+
+#[derive(Debug)]
+struct Carton {}
+
+#[derive(Debug)]
+struct Crate {}
+
+impl Storable for Carton {}
+impl Storable for Crate {}
+
+// NOTE: This example demonstrates that we can call a method on a trait object, but notice that we
+// have to use the `?Sized` bound on the type parameter `S` in the function signature.
+//
+// 38 | pub fn do_something<S>(s: &S) -> &S
+//    |                     ^ required by the implicit `Sized` requirement on this type parameter in `do_something`
+// help: consider relaxing the implicit `Sized` restriction
+//    |
+// 38 | pub fn do_something<S: ?Sized>(s: &S) -> &S
+//    |                      ++++++++
+pub fn do_something<S>(s: &S) -> &S
+where
+    S: ?Sized,
+{
+    let caller_type = std::any::type_name::<S>();
+    tracing::info!("This is {:?}", caller_type);
+
+    s
+}
+
+pub fn main() -> Result<(), Error> {
+    // Set the RUST_LOG, if it hasn't been explicitly defined
+    if std::env::var_os("RUST_LOG").is_none() {
+        std::env::set_var(
+            "RUST_LOG",
+            "tutorials=info,tower_http=trace,tokio=trace,runtime=trace",
+        )
+    }
+    tracing_subscriber::fmt()
+        .with_max_level(tracing::Level::INFO)
+        .with_file(true)
+        .with_line_number(true)
+        .init();
+
+    let item = &Carton {};
+    let holder1 = Holder(item);
+    tracing::info!("holder1: {:?}", holder1);
+    tracing::info!(
+        "holder1: can_return_string(): {:?}",
+        holder1.0.can_return_string()
+    );
+    let item = Crate {};
+    let holder2 = Holder(&item);
+    tracing::info!("holder2: {:?}", holder2);
+    tracing::info!(
+        "holder2: can_return_string(): {:?}",
+        holder2.0.can_return_string()
+    );
+
+    tracing::info!(
+        "need_sized() can be called directly on {:?}",
+        &item.need_sized(),
+    );
+
+    // NOTE: However, we cannot call this on a trait object due to the Sized requirement
+    //
+    // dbg!(holder2.0.need_sized());
+    // error: the `need_sized` method cannot be invoked on a trait object
+    // --> src/bin/sized-1.rs:71:20
+    // |
+    // 19 |         Self: Sized,
+    // |               ----- this has a `Sized` requirement
+    // ...
+    // 71 |     dbg!(holder2.0.need_sized());
+    // |                    ^^^^^^^^^^
+
+    let item = Crate {};
+    let holder = Holder(&item);
+    let s = do_something(holder.0);
+    dbg!(s);
+
+    Ok(())
+}
diff --git a/src/bin/str-1.rs b/src/bin/str-1.rs
new file mode 100644
index 0000000..fe57ad1
--- /dev/null
+++ b/src/bin/str-1.rs
@@ -0,0 +1,42 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use std::fmt::Debug;
+
+use anyhow::Error;
+
+extern crate tutorials;
+
+pub fn main() -> Result<(), Error> {
+    // Set the RUST_LOG, if it hasn't been explicitly defined
+    if std::env::var_os("RUST_LOG").is_none() {
+        std::env::set_var(
+            "RUST_LOG",
+            "tutorials=info,tower_http=trace,tokio=trace,runtime=trace",
+        )
+    }
+    tracing_subscriber::fmt()
+        .with_max_level(tracing::Level::INFO)
+        .with_file(true)
+        .with_line_number(true)
+        .init();
+
+    let mut box_string: Box<str> = String::from("hello").into_boxed_str();
+    box_string.make_ascii_uppercase();
+    tracing::info!("{:?}", box_string);
+
+    let mut vec = Vec::with_capacity(10);
+    vec.extend([1, 2, 3]);
+
+    assert!(vec.capacity() >= 10);
+
+    // NOTE: This erases the capacity of the vector
+    let slice = vec.into_boxed_slice();
+
+    let x = slice.iter().map(|el| *el).collect::<Vec<usize>>();
+    dbg!(x);
+
+    assert_eq!(slice.into_vec().capacity(), 3);
+
+    Ok(())
+}
diff --git a/src/bin/string-search-heaptrack.rs b/src/bin/string-search-heaptrack.rs
new file mode 100644
index 0000000..722ca7b
--- /dev/null
+++ b/src/bin/string-search-heaptrack.rs
@@ -0,0 +1,47 @@
+use crate::tutorials::string_search::core::*;
+use crate::tutorials::utils::generate::phrases;
+use anyhow::Error;
+use rand::{thread_rng, Rng};
+use std::collections::HashMap;
+use std::hint::black_box;
+
+pub fn rng_amount() -> f64 {
+    let mut rng = thread_rng();
+    rng.gen_range(19.0..1.0e2)
+}
+extern crate tutorials;
+
+pub fn main() -> Result<(), Error> {
+    static PHRASE_COUNT: i32 = 10_000;
+    static INVOCATION_COUNT: i32 = 1_000_000;
+
+    let rng_phrases = phrases(PHRASE_COUNT);
+    if let Ok(phrases) = rng_phrases {
+        let items: HashMap<&str, f64> = phrases
+            .iter()
+            .map(|phrase| (phrase.as_str(), rng_amount()))
+            .collect();
+        let hm_keys = &items.keys().map(|el| el.to_owned()).collect::<Vec<&str>>();
+
+        let mut entries = Entries::new();
+        entries.add_many(black_box(items));
+
+        for _loop_idx in 0..INVOCATION_COUNT {
+            // Success, the buyer gets an instant match!
+            let _ = black_box(
+                entries
+                    .search(hm_keys[0], 120.00)
+                    .expect("Unable to search through entries!"),
+            );
+        }
+
+        // let phrase_text = phrases
+        //     .iter()
+        //     .map(|el| format!("\"{}\", ", el))
+        //     .collect::<String>();
+        // dbg!(&phrase_text);
+        println!("Phrases generated: {}", &phrases.len());
+    }
+
+    Ok(())
+}
diff --git a/src/bin/thread-1.rs b/src/bin/thread-1.rs
new file mode 100644
index 0000000..c7692f7
--- /dev/null
+++ b/src/bin/thread-1.rs
@@ -0,0 +1,25 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+
+const NUM_CPUS: u8 = 8;
+
+pub fn run_sim() {
+    let mut handles = Vec::with_capacity(NUM_CPUS as usize);
+
+    let (tx, rx) = kanal::bounded::<()>(NUM_CPUS as usize);
+
+    (0..NUM_CPUS - 1).for_each(|_| {
+        let handle = std::thread::spawn(move || loop {
+
+            //
+        });
+
+        handles.push(handle);
+    })
+}
+
+pub fn main() -> Result<(), Error> {
+    Ok(())
+}
diff --git a/src/bin/tokio-panic-handling.rs b/src/bin/tokio-panic-handling.rs
new file mode 100644
index 0000000..30fc769
--- /dev/null
+++ b/src/bin/tokio-panic-handling.rs
@@ -0,0 +1,29 @@
+//! Correctly handle panic failures in threads spawned with Tokio.
+
+use std::time::Duration;
+use tokio::time::sleep;
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+    let control_path_1 = tokio::spawn(async {
+        println!("control path (path_1)");
+        for i in (0..5).rev() {
+            println!("(path_1) ...{i}");
+            sleep(Duration::from_millis(1000)).await;
+        }
+        panic!("(path_1) BOOOOOOOOOOOOOM!!!!");
+    });
+
+    let control_path_2 = tokio::spawn(async {
+        println!("control path (path_2)");
+        loop {
+            sleep(Duration::from_millis(222)).await;
+            println!("(path_2)");
+        }
+    });
+
+    tokio::select! { // as a bonus you get error handling with _?_
+        v = control_path_1 => v?,
+        v = control_path_2 => v?,
+    }
+}
diff --git a/src/bin/tokio-spawn-1.rs b/src/bin/tokio-spawn-1.rs
new file mode 100644
index 0000000..f645212
--- /dev/null
+++ b/src/bin/tokio-spawn-1.rs
@@ -0,0 +1,8 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+
+pub fn main() -> Result<(), Error> {
+    Ok(())
+}
diff --git a/src/bin/trait-objects-1.rs b/src/bin/trait-objects-1.rs
new file mode 100644
index 0000000..e0138b6
--- /dev/null
+++ b/src/bin/trait-objects-1.rs
@@ -0,0 +1,63 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+
+extern crate tutorials;
+
+fn invoke_trait_object<T: Clonable>(x: &mut dyn Foo<T>) {
+    x.dont_need_sized();
+}
+
+trait Foo<A: Clonable> {
+    fn has_generic(&self, gen: A);
+    fn dont_need_sized(&self);
+    // fn need_sized(self) -> Self;
+    // where
+    //     Self: Sized;
+}
+
+trait Clonable: Clone {
+    fn is_clonable(&self) -> bool;
+}
+
+// Blanket impl on any T that impls the provided traits.
+impl<T> Clonable for T
+where
+    T: std::fmt::Display + std::clone::Clone,
+{
+    fn is_clonable(&self) -> bool {
+        true
+    }
+}
+
+struct S;
+
+impl<A> Foo<A> for S
+where
+    A: Clonable + std::fmt::Display,
+{
+    fn has_generic(&self, gen: A) {
+        let a = gen.is_clonable();
+        let x = gen.clone();
+        let x_ptr = &x as *const A;
+        let x_points_at = unsafe { (*x_ptr).clone() };
+
+        println!("this is x: {}", x_points_at);
+    }
+
+    fn dont_need_sized(&self) {}
+
+    // fn need_sized(self) -> Self {
+    //     Self {}
+    // }
+}
+
+pub fn main() -> Result<(), Error> {
+    let mut s = S {};
+    let x = invoke_trait_object::<String>(&mut s);
+
+    s.has_generic("foo".to_string());
+
+    Ok(())
+}
diff --git a/src/bin/vector-1.rs b/src/bin/vector-1.rs
new file mode 100644
index 0000000..d29219a
--- /dev/null
+++ b/src/bin/vector-1.rs
@@ -0,0 +1,212 @@
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+use anyhow::Error;
+use nalgebra::distance_squared;
+use nalgebra::Point3;
+use nalgebra::SimdComplexField;
+use nalgebra::Vector3;
+use rand::prelude::*;
+use rand::Rng;
+
+pub trait NewtonianMechanics<T: SimdComplexField> {
+    fn get_mass(&self) -> T;
+
+    fn get_position(&self) -> Point3<T>;
+    fn get_velocity(&self) -> Vector3<T>;
+    fn set_position(&mut self, position: Point3<T>);
+    fn set_velocity(&mut self, direction: Vector3<T>);
+
+    fn compute_force_vec(&self, other: &Self) -> Option<Vector3<T>>;
+}
+
+#[derive(Clone, Debug)]
+pub struct PointMass<T: SimdComplexField> {
+    position: Point3<T>,
+    velocity: Vector3<T>,
+    mass: T,
+}
+
+impl<T: SimdComplexField> PointMass<T> {
+    pub fn new(position: Point3<T>, velocity: Vector3<T>, mass: T) -> Self {
+        Self {
+            position,
+            velocity,
+            mass,
+        }
+    }
+}
+
+const G: f32 = 6.67430e-5;
+
+macro_rules! impl_mechanics_for_pointmass {
+    ($t:ty) => {
+        impl NewtonianMechanics<$t> for PointMass<$t> {
+            fn get_mass(&self) -> $t {
+                self.mass
+            }
+
+            fn get_position(&self) -> Point3<$t> {
+                self.position
+            }
+            fn get_velocity(&self) -> Vector3<$t> {
+                self.velocity
+            }
+            fn set_position(&mut self, position: Point3<$t>) {
+                self.position = position;
+            }
+            fn set_velocity(&mut self, velocity: Vector3<$t>) {
+                self.velocity = velocity;
+            }
+
+            fn compute_force_vec(&self, other: &Self) -> Option<Vector3<$t>> {
+                if self.get_position() == other.get_position() {
+                    return None;
+                }
+                let dist2 = distance_squared(&self.get_position(), &other.get_position());
+
+                let force = <$t>::from(G) * self.get_mass() * other.get_mass() / dist2;
+
+                let direction = other.get_position() - self.get_position();
+                dbg!(direction);
+
+                Some((direction * (force)).into())
+            }
+        }
+    };
+}
+
+impl_mechanics_for_pointmass!(f32);
+impl_mechanics_for_pointmass!(f64);
+
+pub type PointMassCollection = Vec<PointMass<f32>>;
+
+#[derive(Clone)]
+pub struct Population {
+    items: PointMassCollection,
+}
+
+impl Population {
+    pub fn new(points: usize) -> Self {
+        Self {
+            items: Vec::with_capacity(points),
+        }
+    }
+
+    pub fn add(&mut self, point_mass: PointMass<f32>) {
+        self.items.push(point_mass);
+    }
+
+    pub fn get(&self) -> &PointMassCollection {
+        &self.items
+    }
+
+    pub fn get_mut(&mut self) -> &mut PointMassCollection {
+        &mut self.items
+    }
+
+    pub fn compute_next_positions(pop1: &mut Population, pop2: &mut Population, ns_per_frame: u64) {
+        let mut p1_items = pop1.get_mut();
+        let p2_items = pop2.get_mut();
+
+        compute_next_positions(&mut p1_items, &p2_items, ns_per_frame);
+    }
+}
+
+pub fn compute_next_positions<T>(
+    next_set: &mut [impl NewtonianMechanics<T>],
+    last_set: &[impl NewtonianMechanics<T>],
+    ns_per_frame: u64,
+) where
+    T: SimdComplexField,
+{
+    let time_const = ns_per_frame as f64 / 1e9;
+
+    for (i, point) in last_set.iter().enumerate() {
+        let mut force = Vector3::new(T::zero(), T::zero(), T::zero());
+
+        for other in last_set.iter() {
+            if let Some(f) = point.compute_force_vec(other) {
+                force += f;
+            } else {
+                continue;
+            }
+        }
+        let acceleration: Vector3<T> = force / point.get_mass();
+        let old_velocity: Vector3<T> = point.get_velocity();
+
+        let new_velocity = old_velocity.clone()
+            + (acceleration * T::from_simd_real(nalgebra::convert(time_const)));
+
+        let new_position = point.get_position() + (old_velocity + new_velocity.clone());
+
+        next_set[i].set_velocity(new_velocity);
+        next_set[i].set_position(new_position);
+    }
+}
+
+pub fn run(num_points: usize, max_init_speed: f32, max_mass: f32, spawn_radius: f32) {
+    let mut population = Population::new(num_points);
+
+    let mut rng = rand::rngs::StdRng::from_entropy();
+
+    population.add(PointMass::new(
+        nalgebra::Point3::new(
+            rng.gen_range(-spawn_radius..spawn_radius),
+            rng.gen_range(-spawn_radius..spawn_radius),
+            rng.gen_range(-spawn_radius..spawn_radius),
+        ),
+        nalgebra::Vector3::new(
+            rng.gen_range(-max_init_speed..max_init_speed),
+            rng.gen_range(-max_init_speed..max_init_speed),
+            rng.gen_range(-max_init_speed..max_init_speed),
+        ),
+        rng.gen_range(1.0..max_mass),
+    ));
+    let mass = rand::random::<f32>() * max_mass;
+
+    dbg!(population.get());
+}
+
+const NUM_ENTITIES: usize = 1;
+const MAX_INIT_SPEED: f32 = 1000.0;
+const MAX_MASS: f32 = 100000000.0;
+const SPAWN_RADIUS: f32 = 10000.0;
+
+pub fn main() -> Result<(), Error> {
+    run(NUM_ENTITIES, MAX_INIT_SPEED, MAX_MASS, SPAWN_RADIUS);
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_compute_force_vec_pre_computed() {
+        let point1 = PointMass::new(Point3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 0.0), 1e4);
+        let point2 = PointMass::new(Point3::new(2.0, 3.0, 6.0), Vector3::new(0.0, 0.0, 0.0), 1e4);
+
+        let force = point1.compute_force_vec(&point2).unwrap();
+        assert_eq!(
+            force,
+            Vector3::new(272.4204060374474, 408.63060905617107, 817.2612181123421)
+        );
+    }
+
+    // FIXME: verify the formula here.
+    #[test]
+    fn test_compute_force_vec_unverified() {
+        let point1 = PointMass::new(Point3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 0.0), 1e4);
+        let point2 = PointMass::new(Point3::new(2.0, 3.0, 6.0), Vector3::new(0.0, 0.0, 0.0), 1e4);
+
+        let force = point1.compute_force_vec(&point2).unwrap();
+        assert!(
+            force
+                - Vector3::new(0.2857142857142857, 0.42857142857142855, 0.8571428571428571) * 1e8
+                    / 49.0
+                < Vector3::new(1e-6, 1e-6, 1e-6)
+        );
+    }
+}
diff --git a/src/builder.rs b/src/builder.rs
index e69de29..f4217ad 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -0,0 +1,42 @@
+#[derive(Debug)]
+pub struct TaskManager {
+    state: String,
+    count: usize,
+}
+
+impl TaskManager {
+    /// Get task count
+    pub fn count(&self) -> &usize {
+        &self.count
+    }
+}
+
+#[derive(Default)]
+pub struct TaskManagerBuilder {
+    state: String,
+    count: usize,
+}
+
+impl TaskManagerBuilder {
+    /// Creates a new TaskManagerBuilder
+    pub fn new() -> Self {
+        Self {
+            state: "initialized".to_string(),
+            count: 0,
+        }
+    }
+
+    /// Sets the task count
+    pub fn count(mut self, value: usize) -> Self {
+        self.count = value;
+        self
+    }
+
+    /// Creates a new TaskManager
+    pub fn build(self) -> TaskManager {
+        TaskManager {
+            state: self.state,
+            count: self.count,
+        }
+    }
+}
diff --git a/src/challenge1.rs b/src/challenge1.rs
new file mode 100644
index 0000000..d1655ac
--- /dev/null
+++ b/src/challenge1.rs
@@ -0,0 +1,251 @@
+/// Example at:
+/// https://gist.github.com/bsodmike/46fc344fa8d5fcb6e30f544bd4409df5
+use anyhow::{Context, Error, Result};
+use hmac::{digest::core_api::CoreWrapper, EagerHash, Hmac, HmacCore, KeyInit};
+use log::trace;
+use pbkdf2::pbkdf2;
+use sha2::Sha512;
+
+type PrfHasher = Sha512;
+
+const PBKDF_ROUNDS: u32 = 600_000;
+const KEY_BUFF_SIZE: usize = 20;
+
+pub fn runner() -> Result<()> {
+    example1::run()?;
+
+    Ok(())
+}
+
+pub mod aes {
+    use aes::cipher;
+    use aes::cipher::generic_array::GenericArray;
+    use aes_gcm_siv::aead::Buffer;
+    use aes_gcm_siv::AesGcmSiv;
+    use aes_gcm_siv::{
+        aead::{AeadInPlace, KeyInit, OsRng},
+        Aes256GcmSiv, Nonce,
+    };
+    use std::io::Read;
+    use std::marker::PhantomData;
+
+    #[derive(Debug)]
+    /// FIXME: Allow swiching out the `A` array type.
+    pub(crate) struct AesVecBuffer<'a, A> {
+        inner: Vec<u8>,
+        _life: PhantomData<&'a A>,
+    }
+
+    impl<'a, A> AesVecBuffer<'a, A> {
+        pub fn inner(&mut self) -> &mut Vec<u8> {
+            &mut self.inner
+        }
+    }
+
+    impl<'a, A> aes_gcm_siv::aead::Buffer for AesVecBuffer<'a, A> {
+        fn extend_from_slice(&mut self, other: &[u8]) -> aes_gcm_siv::aead::Result<()> {
+            Ok(self.inner.extend(other))
+        }
+
+        fn truncate(&mut self, len: usize) {
+            self.inner.truncate(len)
+        }
+
+        fn len(&self) -> usize {
+            self.as_ref().len()
+        }
+
+        fn is_empty(&self) -> bool {
+            self.as_ref().is_empty()
+        }
+    }
+
+    impl<'a, A> AsRef<[u8]> for AesVecBuffer<'a, A> {
+        fn as_ref(&self) -> &[u8] {
+            &self.inner
+        }
+    }
+
+    impl<'a, A> AsMut<[u8]> for AesVecBuffer<'a, A> {
+        fn as_mut(&mut self) -> &mut [u8] {
+            &mut self.inner[..]
+        }
+    }
+
+    impl<'a, A, const N: usize> PartialEq<[u8; N]> for AesVecBuffer<'a, A> {
+        fn eq(&self, other: &[u8; N]) -> bool {
+            self.inner.eq(other)
+        }
+
+        fn ne(&self, other: &[u8; N]) -> bool {
+            !self.eq(other)
+        }
+    }
+
+    pub(crate) struct AesEncrypter<'a> {
+        cipher: AesGcmSiv<aes::Aes256>,
+        nonce: String,
+        buffer: AesVecBuffer<'a, ()>,
+    }
+
+    impl<'a> AesEncrypter<'a> {
+        pub fn new(nonce: String, plaintext: &'a str) -> Self {
+            let key = Aes256GcmSiv::generate_key(&mut OsRng);
+            let cipher = Aes256GcmSiv::new(&key);
+
+            // Note: buffer needs 16-bytes overhead for auth tag tag
+            let inner: heapless::Vec<u8, 128> = heapless::Vec::new();
+            // let inner: Vec<u8> = Vec::new();
+            let mut buffer = AesVecBuffer::<()> {
+                inner: inner.to_vec(),
+                _life: PhantomData,
+            };
+            buffer.extend_from_slice(plaintext.as_bytes()).unwrap();
+
+            Self {
+                cipher,
+                nonce,
+                buffer,
+            }
+        }
+
+        #[allow(dead_code)]
+        pub fn buffer(&mut self) -> &mut AesVecBuffer<'a, ()> {
+            &mut self.buffer
+        }
+
+        pub fn encrypt_in_place(&mut self) -> anyhow::Result<()> {
+            let mut bytes = self.nonce.as_bytes();
+            let mut short_nonce = [0u8; 12];
+            bytes.read_exact(&mut short_nonce)?;
+            // trace!("Len: {:?}", short_nonce.len());
+            let nonce: &GenericArray<u8, cipher::consts::U12> = Nonce::from_slice(&short_nonce[..]); // 96-bits; unique per message
+
+            // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
+            Ok(self
+                .cipher
+                .encrypt_in_place(nonce, b"", &mut self.buffer)
+                .expect("Encrypt cipher in place"))
+        }
+
+        pub fn decrypt_in_place(&mut self) -> anyhow::Result<()> {
+            let mut bytes = self.nonce.as_bytes();
+            let mut short_nonce = [0u8; 12];
+            bytes.read_exact(&mut short_nonce)?;
+
+            let nonce: &GenericArray<u8, cipher::consts::U12> = Nonce::from_slice(&short_nonce[..]); // 96-bits; unique per message
+
+            // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
+            Ok(self
+                .cipher
+                .decrypt_in_place(nonce, b"", &mut self.buffer)
+                .expect("Decrypt cipher in place"))
+        }
+    }
+}
+
+use crate::challenge1::aes::AesEncrypter;
+use crate::challenge1::encrypter::{Encryptable, Encrypter};
+
+pub(crate) struct EncrypterState<'a>(pub(crate) &'a str, pub(crate) &'a str);
+
+impl<'a> EncrypterState<'a> {
+    pub(crate) fn new(password: &'a str, salt: &'a str) -> Self {
+        Self(password, salt)
+    }
+}
+
+pub(crate) fn get_encrypter<'a>(state: EncrypterState<'a>, plaintext: &'a str) -> AesEncrypter<'a> {
+    // Create pbkdf
+    let buf = [0u8; 20];
+    let mut buf_boxed = Box::new(buf);
+    let mut encrypter = Encrypter::<()>::new(&mut buf_boxed);
+    let pbkdf_key = encrypter.pbkdf_key(state.0, state.1);
+    let pbkdf_key_hex = hex::encode(pbkdf_key);
+    trace!("Key: {}", &pbkdf_key_hex);
+
+    AesEncrypter::new(pbkdf_key_hex.clone(), plaintext)
+}
+
+fn process_pbkdf_key<H>(
+    buf_ptr: &mut Box<[u8; KEY_BUFF_SIZE]>,
+    password: &str,
+    salt: &str, // fmt
+) -> anyhow::Result<()>
+where
+    CoreWrapper<HmacCore<H>>: KeyInit,
+    H: hmac::EagerHash,
+    <H as EagerHash>::Core: Sync,
+{
+    let buf = buf_ptr.as_mut();
+
+    pbkdf2::<Hmac<H>>(
+        &password.to_string().as_bytes(),
+        &salt.to_string().as_bytes(),
+        PBKDF_ROUNDS,
+        buf,
+        // fmt
+    )
+    .context("HMAC can be initialized with any key length")?;
+
+    Ok(())
+}
+
+pub mod encrypter {
+    use super::*;
+    use std::marker::PhantomData;
+
+    #[derive(Debug)]
+    pub(crate) struct Encrypter<'a, S> {
+        key: &'a mut Box<[u8; KEY_BUFF_SIZE]>,
+        _phat: PhantomData<&'a S>,
+    }
+
+    impl<'a, S> Encrypter<'a, S> {
+        pub fn new(buf: &'a mut Box<[u8; KEY_BUFF_SIZE]>) -> Self {
+            Self {
+                key: buf,
+                _phat: PhantomData,
+            }
+        }
+    }
+
+    pub trait Encryptable {
+        type KeyBuf;
+
+        fn pbkdf_key(&mut self, password: &str, salt: &str) -> Self::KeyBuf;
+    }
+
+    impl<T> Encryptable for Encrypter<'_, T> {
+        type KeyBuf = [u8; KEY_BUFF_SIZE];
+
+        fn pbkdf_key(&mut self, password: &str, salt: &str) -> Self::KeyBuf {
+            process_pbkdf_key::<PrfHasher>(&mut self.key, password, salt).unwrap();
+
+            **self.key
+        }
+    }
+}
+
+pub mod example1 {
+    use super::*;
+
+    pub fn run() -> Result<()> {
+        let mut enc = get_encrypter(EncrypterState::new("password", "salt"), "plaintext message");
+        enc.encrypt_in_place().unwrap();
+        // `buffer` now contains the message ciphertext
+        trace!("Encrypted cipher text: {}", hex::encode(&enc.buffer()));
+        assert_ne!(enc.buffer(), b"plaintext message");
+
+        // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
+        enc.decrypt_in_place().unwrap();
+        let m = enc.buffer().inner();
+        trace!(
+            "Decrypted plaintext: {}",
+            String::from_utf8(m.to_vec()).unwrap()
+        );
+        assert_eq!(enc.buffer().as_ref(), b"plaintext message");
+
+        Ok(())
+    }
+}
diff --git a/src/cli.rs b/src/cli.rs
index e69de29..fb0fdcd 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -0,0 +1,45 @@
+use anyhow::{Error, Result};
+use clap::{Parser, Subcommand};
+use std::str::FromStr;
+
+/// Program to run rust tutorials
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+pub struct Args {
+    #[clap(subcommand)]
+    pub command: Option<Commands>,
+}
+
+#[derive(Subcommand, Debug)]
+pub enum Commands {
+    /// Tutorial on dynamic dispatch
+    Dispatch,
+
+    /// Builder pattern
+    Builder,
+
+    /// Implementing an Object-Oriented Design Pattern with Type state
+    TypeState,
+
+    /// Smart pointers
+    SmartPointers,
+
+    /// Traits
+    Traits,
+
+    /// Conversion
+    Conversion,
+
+    /// Closures
+    Closures,
+
+    /// Challenge1
+    Challenge1,
+
+    /// PartialEq example
+    PartialEq1,
+}
+
+pub fn runner<T>(mut mk: impl FnMut() -> Result<T>) -> Result<T> {
+    mk()
+}
diff --git a/src/closures.rs b/src/closures.rs
new file mode 100644
index 0000000..051d032
--- /dev/null
+++ b/src/closures.rs
@@ -0,0 +1,209 @@
+use anyhow::{Error, Result};
+use log::info;
+
+#[tokio::main]
+pub async fn runner() -> Result<()> {
+    lesson_1::run().await?;
+    lesson_2::run().await?;
+    lesson_3::run().await?;
+    lesson_4::run()?;
+
+    Ok(())
+}
+
+mod lesson_1 {
+    use super::*;
+    use std::{
+        collections::BTreeMap,
+        fmt::{self, Debug, Display},
+        sync::Arc,
+        time::Duration,
+    };
+    use tokio::{sync::mpsc, task::JoinHandle};
+
+    #[derive(Debug)]
+    pub enum ActorMessage {
+        RunTask {
+            document: String,
+            rows: Vec<u32>,
+            alert: Option<Arc<tokio::sync::oneshot::Sender<bool>>>,
+            timestamp: String,
+        },
+    }
+
+    pub struct MyActor {
+        receiver: mpsc::Receiver<ActorMessage>,
+        next_id: u32,
+    }
+
+    impl MyActor {
+        pub fn new(receiver: mpsc::Receiver<ActorMessage>) -> Self {
+            MyActor {
+                receiver,
+                next_id: 0,
+            }
+        }
+        pub fn spawn_tasks<F, D, R>(mut f: F, d: D, r: R) -> JoinHandle<()>
+        where
+            F: FnMut(D, R) -> JoinHandle<()>,
+        {
+            f(d, r)
+        }
+
+        async fn run_in_parallel<TaskName, ItemCollection, Item>(
+            task_name: TaskName,
+            items: ItemCollection,
+            mut fut: &impl Fn(TaskName, ItemCollection::Item) -> JoinHandle<()>,
+        ) -> Vec<()>
+        where
+            TaskName: Display + Clone,
+            ItemCollection: IntoIterator<Item = Item>,
+        {
+            let futures: Vec<_> = items
+                .into_iter()
+                .map(|row| Self::spawn_tasks(&mut fut, task_name.clone(), row))
+                .collect();
+
+            // do these futures in parallel and return them
+            let mut res = Vec::with_capacity(futures.len());
+            for f in futures.into_iter() {
+                log::info!("run_in_parallel(): {:#?}", &f);
+                f.await.expect("Run `do_task` as a parallel task");
+                res.push(());
+            }
+
+            res
+        }
+
+        async fn do_task(task_name: String, el: u32) {
+            log::info!("do_task(): {} / {}", task_name, el);
+        }
+    }
+
+    pub async fn run() -> Result<()> {
+        let task = "test".to_string();
+        let items: Vec<u32> = vec![0, 1, 2];
+
+        let c = |t, elem| tokio::spawn(MyActor::do_task(t, elem));
+
+        let results = MyActor::run_in_parallel::<String, Vec<u32>, u32>(task, items, &c).await;
+
+        log::info!("run(): done.");
+
+        Ok(())
+    }
+}
+
+mod lesson_2 {
+    use super::*;
+    use std::{fmt::Debug, fs::File, io::Write};
+    trait Writeable: Write + Debug {}
+    impl Writeable for File {}
+
+    fn foo(f: &mut (impl FnMut(i32) -> i32 + ?Sized)) {
+        dbg!(f(5));
+    }
+
+    fn test(v: i32) -> i32 {
+        dbg!(v)
+    }
+
+    fn process_file(f: &mut (dyn Writeable)) {
+        dbg!(f);
+    }
+
+    pub async fn run() -> Result<()> {
+        foo(&mut test); // static dispatch
+
+        let dyn_func: &mut dyn FnMut(i32) -> i32 = &mut test;
+        foo(dyn_func); // dynamic dispatch
+
+        // example with Write trait object
+        let dyn_f: &mut dyn Writeable = &mut File::create("/tmp/test.log").unwrap();
+        process_file(dyn_f);
+
+        log::info!("run(): done.");
+
+        Ok(())
+    }
+}
+
+mod lesson_3 {
+    use super::*;
+
+    pub async fn run() -> Result<()> {
+        fn closures<F1, F2, F3>(
+            mut f1: F1,
+            mut f2: F2,
+            mut f3: F3,
+            mut f4: impl FnMut(usize) -> usize,
+        ) -> i32
+        where
+            F1: FnMut() -> f32,
+            F2: FnMut(i32) -> f32,
+            F3: FnMut(i32, i32) -> f32,
+        {
+            // (f1() + f2(10) + f3(20, 30)) as i32
+            f4(10) as i32
+        }
+
+        let x = closures(|| 0.1, |x| (2 * x) as f32, |x, y| (x + y) as f32, |k| k);
+
+        log::info!("run(): x: {}", x);
+
+        Ok(())
+    }
+}
+
+mod lesson_4 {
+    use super::*;
+
+    /*
+       Least                   Most
+       restrictive:            restrictive
+       FnOnce() --> FnMut() --> Fn()
+       T            &mut T      &T
+    */
+
+    fn exec_once<'a, F: FnOnce(&'a str)>(mut f: F) {
+        f("hola")
+    }
+
+    // https://practice.rs/functional-programing/closure.html#fn-fnmut-fnonce
+    pub fn run() -> Result<()> {
+        // Closure over FnOnce
+        let mut s = String::new();
+        let c = |str| {
+            s; // closure is `FnOnce` because it moves the variable `s` out of its environment
+            ()
+        };
+        exec_once(c);
+        // exec_once(&c); // not allowed
+
+        // Closure over FnMut
+        let mut s = String::new();
+        let mut c = |str| {
+            s.push_str(str);
+            // closure is `FnMut` because it mutates the variable `s` here
+            // this closure implements `FnMut`, not `Fn`
+        };
+        exec_once(&mut c);
+        exec_once(c);
+        // exec_once(&c); // not allowed
+
+        // Closure over Fn
+        let mut s = String::new();
+        let mut c = |str| {
+            let _ = &s;
+            ()
+        };
+        exec_once(c);
+        exec_once(&c);
+        exec_once(&mut c);
+
+        // exec_mut(&mut update_string2);
+        // assert_eq!(s, "hola".to_string());
+
+        Ok(())
+    }
+}
diff --git a/src/conversion.rs b/src/conversion.rs
new file mode 100644
index 0000000..81f2295
--- /dev/null
+++ b/src/conversion.rs
@@ -0,0 +1,128 @@
+use anyhow::Result;
+
+pub fn runner() -> Result<()> {
+    lesson_1()?;
+    lesson_2()?;
+    embedded_rtc::lesson_3()?;
+
+    Ok(())
+}
+
+pub fn lesson_1() -> Result<()> {
+    let value: u8 = 10;
+    let resp: u16 = value.into();
+    assert_eq!(resp as u8, value);
+
+    let resp2 = u16::from(value);
+    assert_eq!(resp, resp2);
+
+    let formal = <u8 as Into<u16>>::into(value);
+    let shorter = value as u16;
+
+    Ok(())
+}
+
+// This is not possible as we cannot convert from u32 to u16 without truncation and data loss.
+//
+// --> src/lib/conversion/mod.rs:13:21
+// |
+// 13 |     let resp: u16 = value.into();
+// |                     ^^^^^ ---- required by a bound introduced by this call
+// |                     |
+// |                     the trait `From<u32>` is not implemented for `u16`
+// |
+// = help: the following other types implement trait `From<T>`:
+//           <f32 as From<i16>>
+//           <f32 as From<i8>>
+//           <f32 as From<u16>>
+//           <f32 as From<u8>>
+//           <f64 as From<f32>>
+//           <f64 as From<i16>>
+//           <f64 as From<i32>>
+//           <f64 as From<i8>>
+//         and 67 others
+// = note: required for `u32` to implement `Into<u16>`
+pub fn lesson_2() -> Result<()> {
+    let value: u32 = 10;
+    // let resp: u16 = value.into();
+
+    Ok(())
+}
+
+pub mod embedded_rtc {
+    use super::*;
+    use std::fmt;
+
+    #[derive(Debug, Clone, Copy)]
+    pub enum Weekday {
+        Sunday = 1,
+        Monday = 2,
+        Tuesday = 4,
+        Wednesday = 8,
+        Thursday = 16,
+        Friday = 32,
+        Saturday = 64,
+    }
+
+    impl fmt::Display for Weekday {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            write!(f, "{}", self.to_s())
+        }
+    }
+
+    impl Weekday {
+        pub fn value(&self) -> u8 {
+            *self as u8
+        }
+
+        pub fn to_s(&self) -> String {
+            match self {
+                Self::Sunday => "Sunday".to_string(),
+                Self::Monday => "Monday".to_string(),
+                Self::Tuesday => "Tuesday".to_string(),
+                Self::Wednesday => "Wednesday".to_string(),
+                Self::Thursday => "Thursday".to_string(),
+                Self::Friday => "Friday".to_string(),
+                Self::Saturday => "Saturday".to_string(),
+            }
+        }
+
+        // Returns the first 3-letters of the day of the week
+        pub fn to_short(&self) -> Result<String> {
+            let day = self.to_s();
+            let result: String = day.chars().take(3).collect();
+
+            Ok(result)
+        }
+    }
+
+    impl From<u8> for Weekday {
+        fn from(day: u8) -> Self {
+            match day {
+                1 => Self::Sunday,
+                2 => Self::Monday,
+                4 => Self::Tuesday,
+                8 => Self::Wednesday,
+                16 => Self::Thursday,
+                32 => Self::Friday,
+                64 => Self::Saturday,
+                _ => Self::Sunday,
+            }
+        }
+    }
+
+    pub fn lesson_3() -> Result<()> {
+        let weekday_num = 4 as u8;
+
+        // This is possible since we added the `From<_>` trait above
+        // via `impl From<u8> for Weekday { //... }`
+        let weekday = Weekday::from(weekday_num);
+
+        let weekday_value = weekday.value();
+        assert_eq!(weekday_value, 4);
+        assert_eq!(weekday.to_s(), "Tuesday");
+        assert_eq!(weekday.to_short()?, "Tue");
+
+        Ok(())
+    }
+}
diff --git a/src/dispatch.rs b/src/dispatch.rs
index e69de29..0a709ec 100644
--- a/src/dispatch.rs
+++ b/src/dispatch.rs
@@ -0,0 +1,59 @@
+/// Say hello in Norwegian
+pub trait Hei {
+    fn hei(&self);
+
+    fn weird(&self);
+
+    fn need_sized(self) -> Self
+    where
+        Self: Sized;
+}
+
+impl Hei for &str {
+    fn hei(&self) {
+        println!("hei {}", self);
+    }
+
+    fn weird(&self) {
+        println!("you called wierd {}", self);
+    }
+
+    fn need_sized(self) -> Self {
+        self
+    }
+}
+
+impl Hei for String {
+    fn hei(&self) {
+        println!("hei {}", self);
+    }
+
+    fn weird(&self) {
+        println!("you called wierd {}", self);
+    }
+
+    fn need_sized(self) -> Self {
+        self
+    }
+}
+
+pub fn say_hei(s: &dyn Hei) {
+    s.hei()
+}
+
+pub fn strlen<S: AsRef<str>>(s: S) -> usize {
+    s.as_ref().len()
+}
+
+pub fn strlen2(s: String) -> usize {
+    s.len()
+}
+
+// examples of trait objects
+pub fn strlen_dyn2(s: Box<dyn AsRef<str>>) -> usize {
+    s.as_ref().as_ref().len()
+}
+
+pub fn strlen_dyn(s: &dyn AsRef<str>) -> usize {
+    s.as_ref().len()
+}
diff --git a/src/lib.rs b/src/lib.rs
index a85656b..d1fdad8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,18 @@
-pub(crate) mod builder;
-pub(crate) mod cli;
-pub(crate) mod dispatch;
-pub(crate) mod oop_pattern;
+pub mod builder;
+pub mod cli;
+pub mod closures;
+pub mod conversion;
+pub mod dispatch;
+pub mod oop_pattern;
+pub mod smart_pointers;
+pub mod traits;
 //mod generics_1;
 //mod iterators_1;
 //mod trait_objects_1;
+pub mod challenge1;
+pub mod partial_eq;
+
+pub mod string_search {
+    pub mod core;
+}
+pub mod utils;
diff --git a/src/lib/builder.rs b/src/lib/builder.rs
deleted file mode 100644
index bcda5bf..0000000
--- a/src/lib/builder.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-#[derive(Debug)]
-pub(crate) struct TaskManager {
-    state: String,
-    count: usize,
-}
-
-impl TaskManager {
-    /// Get task count
-    pub(crate) fn count(&self) -> &usize {
-        &self.count
-    }
-}
-
-#[derive(Default)]
-pub(crate) struct TaskManagerBuilder {
-    state: String,
-    count: usize,
-}
-
-impl TaskManagerBuilder {
-    /// Creates a new TaskManagerBuilder
-    pub(crate) fn new() -> Self {
-        Self {
-            state: "initialized".to_string(),
-            count: 0,
-        }
-    }
-
-    /// Sets the task count
-    pub(crate) fn count(mut self, value: usize) -> Self {
-        self.count = value;
-        self
-    }
-
-    /// Creates a new TaskManager
-    pub(crate) fn build(self) -> TaskManager {
-        TaskManager {
-            state: self.state,
-            count: self.count,
-        }
-    }
-}
diff --git a/src/lib/cli.rs b/src/lib/cli.rs
deleted file mode 100644
index 360d514..0000000
--- a/src/lib/cli.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use clap::{Parser, Subcommand};
-use std::str::FromStr;
-
-/// Program to run rust tutorials
-#[derive(Parser, Debug)]
-#[clap(author, version, about, long_about = None)]
-pub(crate) struct Args {
-    #[clap(subcommand)]
-    pub(crate) command: Option<Commands>,
-}
-
-#[derive(Subcommand, Debug)]
-pub(crate) enum Commands {
-    /// Tutorial on dynamic dispatch
-    Dispatch,
-
-    /// Builder pattern
-    Builder,
-
-    /// Implementing an Object-Oriented Design Pattern with Type state
-    TypeState,
-}
-
-pub(crate) fn runner<T>(mut mk: impl FnMut() -> T) -> T {
-    mk()
-}
diff --git a/src/lib/dispatch.rs b/src/lib/dispatch.rs
deleted file mode 100644
index 882a500..0000000
--- a/src/lib/dispatch.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-/// Say hello in Norwegian
-pub(crate) trait Hei {
-    fn hei(&self);
-
-    fn weird(&self);
-
-    fn need_sized(self) -> Self
-    where
-        Self: Sized;
-}
-
-impl Hei for &str {
-    fn hei(&self) {
-        println!("hei {}", self);
-    }
-
-    fn weird(&self) {
-        println!("you called wierd {}", self);
-    }
-
-    fn need_sized(self) -> Self {
-        self
-    }
-}
-
-impl Hei for String {
-    fn hei(&self) {
-        println!("hei {}", self);
-    }
-
-    fn weird(&self) {
-        println!("you called wierd {}", self);
-    }
-
-    fn need_sized(self) -> Self {
-        self
-    }
-}
-
-pub(crate) fn say_hei(s: &dyn Hei) {
-    s.hei()
-}
-
-pub(crate) fn strlen<S: AsRef<str>>(s: S) -> usize {
-    s.as_ref().len()
-}
-
-pub(crate) fn strlen2(s: String) -> usize {
-    s.len()
-}
-
-// examples of trait objects
-pub(crate) fn strlen_dyn2(s: Box<dyn AsRef<str>>) -> usize {
-    s.as_ref().as_ref().len()
-}
-
-pub(crate) fn strlen_dyn(s: &dyn AsRef<str>) -> usize {
-    s.as_ref().len()
-}
diff --git a/src/lib/oop_pattern.rs b/src/lib/oop_pattern.rs
deleted file mode 100644
index be0b36e..0000000
--- a/src/lib/oop_pattern.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-pub(crate) struct Post {
-    content: String,
-}
-
-pub(crate) struct DraftPost {
-    content: String,
-}
-
-impl Post {
-    pub(crate) fn new() -> DraftPost {
-        DraftPost {
-            content: String::new(),
-        }
-    }
-
-    pub(crate) fn content(&self) -> &str {
-        &self.content
-    }
-}
-
-impl DraftPost {
-    pub(crate) fn add_text(&mut self, text: &str) {
-        self.content.push_str(text);
-    }
-
-    pub(crate) fn request_review(self) -> PendingReviewPost {
-        PendingReviewPost {
-            content: self.content,
-        }
-    }
-}
-
-pub(crate) struct PendingReviewPost {
-    content: String,
-}
-
-impl PendingReviewPost {
-    pub(crate) fn review(&self) -> &String {
-        &self.content
-    }
-
-    pub(crate) fn approve(self) -> Post {
-        Post {
-            content: self.content,
-        }
-    }
-
-    pub(crate) fn reject(self, changes: &str) -> RequestChangesPost {
-        RequestChangesPost {
-            content: self.content,
-            changes: changes.to_string(),
-        }
-    }
-}
-
-pub(crate) struct RequestChangesPost {
-    content: String,
-    changes: String,
-}
-
-impl RequestChangesPost {
-    pub(crate) fn get_feedback(&self) -> String {
-        format!("Make changes to '{}' as {}", &self.content, &self.changes)
-    }
-
-    pub(crate) fn replace_text(&mut self, text: &str) -> PendingReviewPost {
-        PendingReviewPost {
-            content: text.to_string(),
-        }
-    }
-}
diff --git a/src/main.rs b/src/main.rs
index fd725d9..9aecba0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,47 +1,62 @@
 //! This is the main application
 
-#![forbid(unsafe_code)]
+// Disabled for use of UnsafeCell
+//#![forbid(unsafe_code)]
 #![allow(unused_imports)]
-#![deny(unreachable_pub, private_in_public, unstable_features)]
+#![deny(unreachable_pub, unstable_features)]
 #![warn(rust_2018_idioms, future_incompatible, nonstandard_style)]
 
+use anyhow::{Error, Result};
 use clap::Parser;
-use lib::cli::{runner, Args, Commands};
-use lib::{builder::TaskManagerBuilder, dispatch::*, oop_pattern::*};
 use log::{debug, info};
-
-mod lib;
-
-fn main() {
+use std::io::Read;
+use std::sync::Arc;
+use tutorials::cli::{runner, Args, Commands};
+use tutorials::{
+    builder::TaskManagerBuilder, closures, dispatch::*, oop_pattern::*, smart_pointers::*, traits,
+};
+use tutorials::{challenge1, partial_eq};
+
+fn main() -> Result<()> {
     env_logger::init();
 
     let cli = Args::parse();
 
+    // FIXME - what was this about now?
+    // let f = vec![];
+    // let s = || {
+    //     //
+    // };
+
     match &cli.command {
-        Some(Commands::Dispatch) => runner(|| {
-            info!("Tutorial: Dynamic dispatch\n");
-
-            let x: Box<dyn AsRef<str>> = Box::new("hello".to_string());
-            strlen_dyn2(x);
-
-            // Use go-through pointer-indirection for something on the stack
-            let x: &dyn AsRef<str> = &"hello".to_string();
-            strlen_dyn(x);
-
-            // Use our Hei trait
-            let x: &dyn Hei = &"hei".to_string();
-            x.weird();
-            //x.need_sized();   // This is not object safe and therefore cannot be called on a trait-object
-            say_hei(x);
-
-            // Demonstrate that sized functions work just fine on any standard implementation of the trait
-            let message = String::from("hello!");
-            message.need_sized().to_string();
-
-            let x: &dyn Hei = &"hei";
-            x.weird();
-            say_hei(x);
-        }),
+        Some(Commands::Dispatch) => {
+            runner(|| {
+                info!("Tutorial: Dynamic dispatch\n");
+
+                let x: Box<dyn AsRef<str>> = Box::new("hello".to_string());
+                strlen_dyn2(x);
+
+                // Use go-through pointer-indirection for something on the stack
+                let x: &dyn AsRef<str> = &"hello".to_string();
+                strlen_dyn(x);
+
+                // Use our Hei trait
+                let x: &dyn Hei = &"hei".to_string();
+                x.weird();
+                //x.need_sized();   // This is not object safe and therefore cannot be called on a trait-object
+                say_hei(x);
+
+                // Demonstrate that sized functions work just fine on any standard implementation of the trait
+                let message = String::from("hello!");
+                message.need_sized().to_string();
+
+                let x: &dyn Hei = &"hei";
+                x.weird();
+                say_hei(x);
+
+                Ok(())
+            })?
+        }
         Some(Commands::Builder) => runner(|| {
             info!("Tutorial: Builder pattern\n");
 
@@ -49,26 +64,112 @@ fn main() {
 
             debug!("Task manager.count: {}", task_manager.count());
             assert_eq!(*task_manager.count(), 10);
-        }),
-        Some(Commands::TypeState) => {
-            runner(|| {
-                info!("Tutorial: OOP design pattern with Type State\n");
 
-                let mut post = Post::new();
-                post.add_text("I ate a salad for lunch today");
+            Ok(())
+        })?,
+        Some(Commands::TypeState) => runner(|| {
+            info!("Tutorial: OOP design pattern with Type State\n");
+
+            let mut post = Post::new();
+            post.add_text("I ate a salad for lunch today");
 
-                let post = post.request_review();
-                assert_eq!("I ate a salad for lunch today", post.review());
+            let post = post.request_review();
+            assert_eq!("I ate a salad for lunch today", post.review());
 
-                let mut post = post.reject("Salad isn't available today");
-                assert_eq!("Make changes to 'I ate a salad for lunch today' as Salad isn't available today", post.get_feedback());
+            let mut post = post.reject("Salad isn't available today");
+            assert_eq!(
+                "Make changes to 'I ate a salad for lunch today' as Salad isn't available today",
+                post.get_feedback()
+            );
 
-                let post = post.replace_text("I ate fish at lunch");
+            let post = post.replace_text("I ate fish at lunch");
 
-                let post = post.approve();
-                assert_eq!("I ate fish at lunch", post.content());
-            })
+            let post = post.approve();
+            assert_eq!("I ate fish at lunch", post.content());
+            Ok(())
+        })?,
+        Some(Commands::SmartPointers) => {
+            runner(|| {
+                info!("Tutorial: Smart pointers\n");
+
+                let new_message = MessageBuilder::new().content("hello").build();
+                let new_message = new_message.update("foo");
+
+                let byte_zero: u8 = 0;
+                assert_ne!(new_message.bytes(), &vec![byte_zero]);
+
+                let message = new_message.update("Häagen-Dazs");
+                assert_eq!(
+                    message.content_from_bytes().unwrap(),
+                    "Häagen-Dazs".to_string()
+                );
+
+                // Example of using a new-type to implement the Into trait
+                struct BytesToString {
+                    value: String,
+                }
+
+                impl BytesToString {
+                    pub(crate) fn new(value: &Vec<u8>) -> Self {
+                        Self {
+                            value: String::from_utf8(value.clone()).unwrap_or_default(),
+                        }
+                    }
+                }
+
+                impl Into<String> for BytesToString {
+                    fn into(self) -> String {
+                        self.value
+                    }
+                }
+
+                let x = Cell::new(message.bytes());
+
+                // BytesToString is used as a new-type to convert Vec<u8> to a String
+                let contents: String = BytesToString::new(x.get()).into();
+                assert_eq!(contents, "Häagen-Dazs".to_string());
+
+                Ok(())
+            })?
         }
+        Some(Commands::Traits) => runner(|| {
+            info!("Tutorial: Traits\n");
+
+            traits::runner()?;
+
+            Ok(())
+        })?,
+        Some(Commands::Conversion) => runner(|| {
+            info!("Tutorial: Conversion\n");
+
+            tutorials::conversion::runner()?;
+
+            Ok(())
+        })?,
+        Some(Commands::Closures) => runner(|| {
+            info!("Tutorial: Closures\n");
+
+            closures::runner()?;
+
+            Ok(())
+        })?,
+        Some(Commands::Challenge1) => runner(|| {
+            info!("Tutorial: Challenge1\n");
+
+            challenge1::runner()?;
+
+            Ok(())
+        })?,
+        Some(Commands::PartialEq1) => runner(|| {
+            info!("Tutorial: PartialEq1\n");
+
+            partial_eq::runner()?;
+
+            Ok(())
+        })?,
+
         _ => info!("Command not found"),
     };
+
+    Ok(())
 }
diff --git a/src/oop_pattern.rs b/src/oop_pattern.rs
index e69de29..2826c62 100644
--- a/src/oop_pattern.rs
+++ b/src/oop_pattern.rs
@@ -0,0 +1,71 @@
+pub struct Post {
+    content: String,
+}
+
+pub struct DraftPost {
+    content: String,
+}
+
+impl Post {
+    pub fn new() -> DraftPost {
+        DraftPost {
+            content: String::new(),
+        }
+    }
+
+    pub fn content(&self) -> &str {
+        &self.content
+    }
+}
+
+impl DraftPost {
+    pub fn add_text(&mut self, text: &str) {
+        self.content.push_str(text);
+    }
+
+    pub fn request_review(self) -> PendingReviewPost {
+        PendingReviewPost {
+            content: self.content,
+        }
+    }
+}
+
+pub struct PendingReviewPost {
+    content: String,
+}
+
+impl PendingReviewPost {
+    pub fn review(&self) -> &String {
+        &self.content
+    }
+
+    pub fn approve(self) -> Post {
+        Post {
+            content: self.content,
+        }
+    }
+
+    pub fn reject(self, changes: &str) -> RequestChangesPost {
+        RequestChangesPost {
+            content: self.content,
+            changes: changes.to_string(),
+        }
+    }
+}
+
+pub struct RequestChangesPost {
+    content: String,
+    changes: String,
+}
+
+impl RequestChangesPost {
+    pub fn get_feedback(&self) -> String {
+        format!("Make changes to '{}' as {}", &self.content, &self.changes)
+    }
+
+    pub fn replace_text(&mut self, text: &str) -> PendingReviewPost {
+        PendingReviewPost {
+            content: text.to_string(),
+        }
+    }
+}
diff --git a/src/partial_eq.rs b/src/partial_eq.rs
new file mode 100644
index 0000000..6295d8e
--- /dev/null
+++ b/src/partial_eq.rs
@@ -0,0 +1,45 @@
+use anyhow::{Ok, Result};
+
+#[derive(Debug, PartialEq, Default)]
+pub struct List<T> {
+    memory: Vec<T>,
+}
+
+impl<T> List<T>
+where
+    List<T>: PartialEq,
+{
+    pub fn new() -> Self {
+        List { memory: Vec::new() }
+    }
+    // push() add to end of list
+    pub fn push(&mut self, value: T) {
+        self.memory.push(value);
+    }
+
+    pub fn is_equal_to(&mut self, other: &List<T>) -> bool {
+        self == other
+    }
+}
+
+pub fn runner() -> Result<()> {
+    example1::run()?;
+
+    Ok(())
+}
+
+pub mod example1 {
+    use super::*;
+
+    pub fn run() -> Result<()> {
+        let mut list1 = List::<Option<usize>>::new();
+        let mut list2 = List::<Option<usize>>::new();
+
+        list1.push(Some(1));
+
+        let are_they_equal = list1.is_equal_to(&mut list2);
+        assert!(are_they_equal);
+
+        Ok(())
+    }
+}
diff --git a/src/generics_1/mod.rs b/src/sandbox/generics_1/mod.rs
similarity index 100%
rename from src/generics_1/mod.rs
rename to src/sandbox/generics_1/mod.rs
diff --git a/src/iterators_1/mod.rs b/src/sandbox/iterators_1/mod.rs
similarity index 99%
rename from src/iterators_1/mod.rs
rename to src/sandbox/iterators_1/mod.rs
index e12e98b..ef2d405 100644
--- a/src/iterators_1/mod.rs
+++ b/src/sandbox/iterators_1/mod.rs
@@ -17,7 +17,7 @@ fn shoes_into_iter(shoes: MyVec<Vec<Shoe>>, shoe_size: u32) -> MyVec<Vec<Shoe>>
 }
 
 #[derive(PartialEq, Debug, Clone)]
-struct MyVec<T>(T);
+pub struct MyVec<T>(T);
 
 struct MyVecIter<'a, T> {
     vector: &'a T,
diff --git a/src/sandbox/mod.rs b/src/sandbox/mod.rs
new file mode 100644
index 0000000..99c03fc
--- /dev/null
+++ b/src/sandbox/mod.rs
@@ -0,0 +1,3 @@
+pub mod generics_1;
+pub mod iterators_1;
+pub mod trait_objects_1;
diff --git a/src/trait_objects_1/mod.rs b/src/sandbox/trait_objects_1/mod.rs
similarity index 100%
rename from src/trait_objects_1/mod.rs
rename to src/sandbox/trait_objects_1/mod.rs
diff --git a/src/smart_pointers.rs b/src/smart_pointers.rs
new file mode 100644
index 0000000..19e72f2
--- /dev/null
+++ b/src/smart_pointers.rs
@@ -0,0 +1,86 @@
+use std::cell::UnsafeCell;
+
+// Further coverage of Cell, RefCell and Rc (https://youtu.be/8O0Nt9qY_vo):
+// https://gist.github.com/jonhoo/7cfdfe581e5108b79c2a4e9fbde38de8
+
+pub struct Cell<T> {
+    value: UnsafeCell<T>,
+}
+
+// implied by UnsafeCell
+// impl<T> !Sync for Cell<T>
+// https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html#impl-Sync
+
+impl<T> Cell<T> {
+    pub fn new(value: T) -> Self {
+        Cell {
+            value: UnsafeCell::new(value),
+        }
+    }
+
+    pub fn set(&self, value: T) {
+        // SAFETY: we know no-one else is concurrently mutating self (because !Sync)
+        // SAFETY: we're not invalidating any references as we are not sharing any.
+        unsafe { *self.value.get() = value };
+    }
+
+    pub fn get(&self) -> T
+    where
+        T: Copy,
+    {
+        // SAFETY: we know no-one else is concurrently mutating this value, since only this thread
+        // can mutate (because !Sync) and it is executing this function
+        unsafe { *self.value.get() }
+    }
+}
+
+/// Contrived example storing a String as Vec<u8>
+pub struct Message {
+    content: String,
+    bytes: Vec<u8>,
+}
+
+impl Message {
+    pub fn update(mut self, content: &str) -> Self {
+        let bytes: Vec<u8> = content.to_string().as_bytes().to_vec();
+        self.bytes = bytes;
+
+        self
+    }
+
+    pub fn content_from_bytes(&self) -> Option<String> {
+        Some(String::from_utf8(self.bytes.clone()).ok()?)
+    }
+
+    pub fn content(&self) -> &String {
+        &self.content
+    }
+
+    pub fn bytes(&self) -> &Vec<u8> {
+        &self.bytes
+    }
+}
+
+pub struct MessageBuilder {
+    content: String,
+}
+
+impl MessageBuilder {
+    pub fn new() -> Self {
+        Self {
+            content: String::default(),
+        }
+    }
+
+    pub fn content(mut self, content: &str) -> Self {
+        self.content = content.to_string();
+        self
+    }
+
+    pub fn build(&self) -> Message {
+        Message {
+            content: self.content.to_string(),
+            bytes: vec![0],
+        }
+    }
+}
diff --git a/src/string_search/core.rs b/src/string_search/core.rs
new file mode 100644
index 0000000..d1e134f
--- /dev/null
+++ b/src/string_search/core.rs
@@ -0,0 +1,144 @@
+//! Challenge:
+//!
+//! - Assume two users are using a site like eBay, but the concept is that user Bob can post an item for sale via a text input field and offer a sell price.
+//! - The bidding action is performed purely in memory, so ignore I/O and other complexities.
+//! - Think in terms of C++ and pointers.  This is a quiz on simple data structures.
+//! - Optimise for Big O performance.
+//!
+//! Design notes:
+//!
+//! - User input is assumed to be all lower case, alphanumerals only, with single spaces.  The assumption is that this binary operates on clean data.  Validating and sanitising input is a further refinement.
+//! - TBD
+//!
+//! Optimisations:
+//!
+//! Create small and big benchmarks:
+//!
+//! - Use https://github.com/bheisler/criterion.rs
+//! - Use https://github.com/nvzqz/divan
+//!
+//! Benchmarking and Profiling:
+//!
+//! Refer to `benchmarking/README.md`
+//!
+//! Tests:
+//!
+//! Run `test-string-search.sh`
+//!
+use anyhow::anyhow;
+use anyhow::Error;
+use std::collections::HashMap;
+
+pub struct Entries(pub HashMap<String, f64>);
+
+impl Entries {
+    pub fn new() -> Self {
+        Self(HashMap::new())
+    }
+
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    pub fn add(&mut self, info: (String, f64)) {
+        let (text, amount) = info;
+        self.0.insert(text, amount);
+    }
+
+    pub fn add_many<'a>(&mut self, items: impl IntoIterator<Item = (&'a str, f64)>) {
+        let new: HashMap<String, f64> =
+            items.into_iter().map(|(k, v)| (k.to_string(), v)).collect();
+        self.0 = new;
+    }
+
+    pub fn search(&mut self, needle: &str, offered_amount: f64) -> Result<f64, Error> {
+        log::debug!("Number of items to search: {}", self.0.len());
+
+        if let Some(cost) = self.0.get(needle) {
+            if offered_amount >= *cost {
+                Ok(*cost)
+            } else {
+                return Err(anyhow!(
+                    "Item {} costs more than your offer of ${}",
+                    &needle,
+                    &offered_amount
+                ));
+            }
+        } else {
+            return Err(anyhow!("Item {} is not available!", &needle));
+        }
+    }
+}
+
+#[cfg(test)]
+pub mod tests {
+    use super::Entries;
+    use crate::utils::generate::phrases;
+    use rand::{thread_rng, Rng};
+    use std::collections::HashMap;
+    use std::hint::black_box;
+
+    pub fn rng_amount() -> f64 {
+        let mut rng = thread_rng();
+        rng.gen_range(19.0..1.0e2)
+    }
+
+    #[test]
+    fn match_existing_available_item() {
+        static PHRASE_COUNT: i32 = 10_000;
+        let rng_phrases = phrases(PHRASE_COUNT);
+
+        if let Ok(phrases) = rng_phrases {
+            let items: HashMap<&str, f64> = phrases
+                .iter()
+                .map(|phrase| (phrase.as_str(), rng_amount()))
+                .collect();
+            let hm_keys = &items.keys().map(|el| el.to_owned()).collect::<Vec<&str>>();
+
+            let mut entries = Entries::new();
+            entries.add_many(black_box(items));
+            assert!(entries.len() > 0);
+
+            // Success, the buyer gets an instant match!
+            let _ = black_box(entries.search(hm_keys[0], 120.00).unwrap());
+        }
+    }
+
+    #[test]
+    fn panic_expect_error_for_low_bid() {
+        let items = HashMap::from([("red apple", 20.0), ("ferrari", 32.1), ("banana", 12.99)]);
+        let mut entries = Entries::new();
+        entries.add_many(black_box(items));
+
+        if let Err(err) = entries.search("banana", 8.23) {
+            assert_eq!(
+                err.to_string(),
+                String::from("Item banana costs more than your offer of $8.23")
+            )
+        }
+    }
+
+    #[should_panic]
+    #[test]
+    fn handle_mismatching_category() {
+        let items = HashMap::from([("red apple", 20.0), ("ferrari", 32.1), ("banana", 12.99)]);
+        let mut entries = Entries::new();
+        entries.add_many(black_box(items));
+
+        entries.search("fruit", 20.00).unwrap();
+    }
+
+    #[test]
+    fn panic_mismatching_category_partial_text() {
+        let items = HashMap::from([("red apple", 20.0), ("ferrari", 32.1), ("banana", 12.99)]);
+        let mut entries = Entries::new();
+        entries.add_many(black_box(items));
+
+        if let Err(err) = entries.search("red appl", 8.23) {
+            assert_eq!(
+                err.to_string(),
+                String::from("Item red appl is not available!")
+            )
+        }
+    }
+}
diff --git a/src/string_search/run-flamegraph.sh b/src/string_search/run-flamegraph.sh
new file mode 100755
index 0000000..7c8ecc0
--- /dev/null
+++ b/src/string_search/run-flamegraph.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -e
+
+cargo b --bin string-search-heaptrack --release
+cargo t --lib
+cargo flamegraph --root --flamechart --verbose --bin string-search-heaptrack
\ No newline at end of file
diff --git a/src/string_search/run-heaptrack.sh b/src/string_search/run-heaptrack.sh
new file mode 100755
index 0000000..cca6197
--- /dev/null
+++ b/src/string_search/run-heaptrack.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+cargo build --bin string-search-heaptrack --release
+heaptrack target/release/string-search-heaptrack
\ No newline at end of file
diff --git a/src/traits.rs b/src/traits.rs
new file mode 100644
index 0000000..affddfa
--- /dev/null
+++ b/src/traits.rs
@@ -0,0 +1,1962 @@
+use anyhow::{Error, Result};
+use log::info;
+use std::{
+    error::Error as StdError,
+    fmt::{self, Display},
+};
+
+// Lesson 1
+pub fn x(b: Box<impl Display + 'static>) -> Box<dyn Display> {
+    b
+}
+
+#[derive(Debug)]
+struct Device(u8);
+
+impl Device {
+    fn new(id: u8) -> Self {
+        Self(id)
+    }
+}
+
+// This is added to satisfy the trait bound on `x`
+impl Display for Device {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_fmt(format_args!("Device ({})", self.0))
+    }
+}
+
+// Error
+pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
+
+#[derive(Debug)]
+pub struct BlanketError {
+    inner: BoxError,
+}
+
+impl BlanketError {
+    /// Create a new `Error` from a boxable error.
+    pub fn new(error: impl Into<BoxError>) -> Self {
+        Self {
+            inner: error.into(),
+        }
+    }
+
+    /// Convert an `Error` back into the underlying boxed trait object.
+    pub fn into_inner(self) -> BoxError {
+        self.inner
+    }
+}
+
+impl fmt::Display for BlanketError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+impl StdError for BlanketError {
+    fn source(&self) -> Option<&(dyn StdError + 'static)> {
+        Some(&*self.inner)
+    }
+}
+
+// Lesson 2: Traits
+pub trait RTC {
+    type Error: ErrorType;
+}
+
+pub trait ErrorType: Display {
+    /// Error type
+    type Error: std::error::Error;
+}
+
+// What does this do exactly?
+impl<T: ErrorType> ErrorType for &mut T {
+    type Error = T::Error;
+}
+
+impl ErrorType for BlanketError {
+    type Error = Self;
+}
+
+struct RTCDevice(u8);
+
+impl RTC for RTCDevice {
+    type Error = BlanketError;
+}
+
+impl fmt::Display for RTCDevice {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl ErrorType for RTCDevice {
+    type Error = BlanketError;
+}
+
+pub fn runner() -> Result<()> {
+    lesson_1_add_trait_bound_to_parameter();
+    lesson_2();
+    lesson_3::run()?;
+    // lesson_4::run();
+    // lesson_5::run();
+
+    // lesson6::run();
+    lesson7::run();
+    let _ = lesson8::run();
+    let _ = lesson9::run();
+    lesson10::run();
+
+    Ok(())
+}
+/// Use `esp_idf_hal` as an example for advanced used of Traits and trait objects
+mod lesson_3 {
+    use crate::{
+        into_ref,
+        traits::lesson_3::peripheral::{Peripheral, PeripheralRef},
+    };
+    use anyhow::Result;
+
+    mod core {
+
+        #[macro_export]
+        #[allow(unused_macros)]
+        macro_rules! into_ref {
+            ($($name:ident),*) => {
+                $(
+                    let $name = $name.into_ref();
+                )*
+            }
+        }
+
+        #[allow(unused_macros)]
+        macro_rules! impl_peripheral_trait {
+            ($type:ident) => {
+                unsafe impl Send for $type {}
+
+                impl $crate::traits::lesson_3::peripheral::sealed::Sealed for $type {}
+
+                impl $crate::traits::lesson_3::peripheral::Peripheral for $type {
+                    type P = $type;
+
+                    #[inline]
+                    unsafe fn clone_unchecked(&mut self) -> Self::P {
+                        $type { ..*self }
+                    }
+                }
+            };
+        }
+
+        #[allow(unused_macros)]
+        macro_rules! impl_peripheral {
+            ($type:ident) => {
+                pub struct $type(::core::marker::PhantomData<*const ()>);
+
+                impl $type {
+                    /// # Safety
+                    ///
+                    /// Care should be taken not to instnatiate this peripheralinstance, if it is already instantiated and used elsewhere
+                    #[inline(always)]
+                    pub unsafe fn new() -> Self {
+                        $type(::core::marker::PhantomData)
+                    }
+                }
+
+                $crate::traits::lesson_3::core::impl_peripheral_trait!($type);
+            };
+        }
+
+        #[allow(unused_imports)]
+        pub(crate) use impl_peripheral;
+        #[allow(unused_imports)]
+        pub(crate) use impl_peripheral_trait;
+        #[allow(unused_imports)]
+        pub(crate) use into_ref;
+    }
+
+    mod peripheral {
+        use core::marker::PhantomData;
+        use core::ops::{Deref, DerefMut};
+
+        pub struct PeripheralRef<'a, T> {
+            inner: T,
+            _lifetime: PhantomData<&'a mut T>,
+        }
+
+        impl<'a, T> PeripheralRef<'a, T> {
+            #[inline]
+            pub fn new(inner: T) -> Self {
+                Self {
+                    inner,
+                    _lifetime: PhantomData,
+                }
+            }
+
+            /// Unsafely clone (duplicate) a Peripheral singleton.
+            ///
+            /// # Safety
+            ///
+            /// This returns an owned clone of the Peripheral. You must manually ensure
+            /// only one copy of the Peripheral is in use at a time. For example, don't
+            /// create two SPI drivers on `SPI1`, because they will "fight" each other.
+            ///
+            /// You should strongly prefer using `reborrow()` instead. It returns a
+            /// `PeripheralRef` that borrows `self`, which allows the borrow checker
+            /// to enforce this at compile time.
+            pub unsafe fn clone_unchecked(&mut self) -> PeripheralRef<'a, T>
+            where
+                T: Peripheral<P = T>,
+            {
+                PeripheralRef::new(self.inner.clone_unchecked())
+            }
+
+            /// Reborrow into a "child" PeripheralRef.
+            ///
+            /// `self` will stay borrowed until the child PeripheralRef is dropped.
+            pub fn reborrow(&mut self) -> PeripheralRef<'_, T>
+            where
+                T: Peripheral<P = T>,
+            {
+                // safety: we're returning the clone inside a new PeripheralRef that borrows
+                // self, so user code can't use both at the same time.
+                PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
+            }
+
+            /// Map the inner Peripheral using `Into`.
+            ///
+            /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, using an
+            /// `Into` impl to convert from `T` to `U`.
+            ///
+            /// For example, this can be useful to degrade GPIO pins: converting from PeripheralRef<'a, PB11>` to `PeripheralRef<'a, AnyPin>`.
+            #[inline]
+            pub fn map_into<U>(self) -> PeripheralRef<'a, U>
+            where
+                T: Into<U>,
+            {
+                PeripheralRef {
+                    inner: self.inner.into(),
+                    _lifetime: PhantomData,
+                }
+            }
+        }
+
+        impl<'a, T> Deref for PeripheralRef<'a, T> {
+            type Target = T;
+
+            #[inline]
+            fn deref(&self) -> &Self::Target {
+                &self.inner
+            }
+        }
+
+        impl<'a, T> DerefMut for PeripheralRef<'a, T> {
+            #[inline]
+            fn deref_mut(&mut self) -> &mut Self::Target {
+                &mut self.inner
+            }
+        }
+
+        /// Trait for any type that can be used as a Peripheral of type `P`.
+        ///
+        /// This is used in driver constructors, to allow passing either owned Peripherals (e.g. `TWISPI0`),
+        /// or borrowed Peripherals (e.g. `&mut TWISPI0`).
+        ///
+        /// For example, if you have a driver with a constructor like this:
+        ///
+        /// ```ignore
+        /// impl<'d, T: Instance> Twim<'d, T> {
+        ///     pub fn new(
+        ///         twim: impl Peripheral<P = T> + 'd,
+        ///         irq: impl Peripheral<P = T::Interrupt> + 'd,
+        ///         sda: impl Peripheral<P = impl GpioPin> + 'd,
+        ///         scl: impl Peripheral<P = impl GpioPin> + 'd,
+        ///         config: Config,
+        ///     ) -> Self { .. }
+        /// }
+        /// ```
+        ///
+        /// You may call it with owned Peripherals, which yields an instance that can live forever (`'static`):
+        ///
+        /// ```ignore
+        /// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
+        /// ```
+        ///
+        /// Or you may call it with borrowed Peripherals, which yields an instance that can only live for as long
+        /// as the borrows last:
+        ///
+        /// ```ignore
+        /// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
+        /// ```
+        ///
+        /// # Implementation details, for HAL authors
+        ///
+        /// When writing a HAL, the intended way to use this trait is to take `impl Peripheral<P = ..>` in
+        /// the HAL's public API (such as driver constructors), calling `.into_ref()` to obtain a `PeripheralRef`,
+        /// and storing that in the driver struct.
+        ///
+        /// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`.
+        /// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`.
+        pub trait Peripheral: Sized + sealed::Sealed {
+            /// Peripheral singleton type
+            type P;
+
+            /// Unsafely clone (duplicate) a Peripheral singleton.
+            ///
+            /// # Safety
+            ///
+            /// This returns an owned clone of the Peripheral. You must manually ensure
+            /// only one copy of the Peripheral is in use at a time. For example, don't
+            /// create two SPI drivers on `SPI1`, because they will "fight" each other.
+            ///
+            /// You should strongly prefer using `into_ref()` instead. It returns a
+            /// `PeripheralRef`, which allows the borrow checker to enforce this at compile time.
+            unsafe fn clone_unchecked(&mut self) -> Self::P;
+
+            /// Convert a value into a `PeripheralRef`.
+            ///
+            /// When called on an owned `T`, yields a `PeripheralRef<'static, T>`.
+            /// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`.
+            #[inline]
+            fn into_ref<'a>(mut self) -> PeripheralRef<'a, Self::P>
+            where
+                Self: 'a,
+            {
+                PeripheralRef::new(unsafe { self.clone_unchecked() })
+            }
+        }
+
+        impl<T: DerefMut> sealed::Sealed for T {}
+
+        impl<T: DerefMut> Peripheral for T
+        where
+            T::Target: Peripheral,
+        {
+            type P = <T::Target as Peripheral>::P;
+
+            #[inline]
+            unsafe fn clone_unchecked(&mut self) -> Self::P {
+                self.deref_mut().clone_unchecked()
+            }
+        }
+
+        pub(crate) mod sealed {
+            pub trait Sealed {}
+        }
+    }
+
+    pub(crate) mod gpio {
+        use super::core::impl_peripheral_trait;
+        use super::peripheral::{Peripheral, PeripheralRef};
+        use anyhow::Result;
+        use core::marker::PhantomData;
+
+        /// A trait implemented by every pin instance
+        pub trait Pin: Peripheral<P = Self> + Sized + Send + 'static {
+            fn pin(&self) -> i32;
+        }
+
+        /// A marker trait designating a pin which is capable of
+        /// operating as an input pin
+        pub trait InputPin: Pin + Into<AnyInputPin> {
+            fn downgrade_input(self) -> AnyInputPin {
+                self.into()
+            }
+        }
+
+        /// A marker trait designating a pin which is capable of
+        /// operating as an output pin
+        pub trait OutputPin: Pin + Into<AnyOutputPin> {
+            fn downgrade_output(self) -> AnyOutputPin {
+                self.into()
+            }
+        }
+
+        /// A marker trait designating a pin which is capable of
+        /// operating as an input and output pin
+        pub trait IOPin: InputPin + OutputPin + Into<AnyIOPin> {
+            fn downgrade(self) -> AnyIOPin {
+                self.into()
+            }
+        }
+
+        /// Generic Gpio input-output pin
+        pub struct AnyIOPin {
+            pin: i32,
+            _p: PhantomData<*const ()>,
+        }
+
+        impl AnyIOPin {
+            /// # Safety
+            ///
+            /// Care should be taken not to instantiate this Pin, if it is
+            /// already instantiated and used elsewhere, or if it is not set
+            /// already in the mode of operation which is being instantiated
+            pub unsafe fn new(pin: i32) -> Self {
+                Self {
+                    pin,
+                    _p: PhantomData,
+                }
+            }
+        }
+
+        impl_peripheral_trait!(AnyIOPin);
+
+        impl Pin for AnyIOPin {
+            fn pin(&self) -> i32 {
+                self.pin
+            }
+        }
+
+        impl InputPin for AnyIOPin {}
+        impl OutputPin for AnyIOPin {}
+
+        /// Generic Gpio input pin
+        pub struct AnyInputPin {
+            pin: i32,
+            _p: PhantomData<*const ()>,
+        }
+
+        impl AnyInputPin {
+            /// # Safety
+            ///
+            /// Care should be taken not to instantiate this Pin, if it is
+            /// already instantiated and used elsewhere, or if it is not set
+            /// already in the mode of operation which is being instantiated
+            pub unsafe fn new(pin: i32) -> Self {
+                Self {
+                    pin,
+                    _p: PhantomData,
+                }
+            }
+        }
+
+        impl_peripheral_trait!(AnyInputPin);
+
+        impl Pin for AnyInputPin {
+            fn pin(&self) -> i32 {
+                self.pin
+            }
+        }
+
+        impl InputPin for AnyInputPin {}
+
+        impl From<AnyIOPin> for AnyInputPin {
+            fn from(pin: AnyIOPin) -> Self {
+                unsafe { Self::new(pin.pin()) }
+            }
+        }
+
+        /// Generic Gpio output pin
+        pub struct AnyOutputPin {
+            pin: i32,
+            _p: PhantomData<*const ()>,
+        }
+
+        impl AnyOutputPin {
+            /// # Safety
+            ///
+            /// Care should be taken not to instantiate this Pin, if it is
+            /// already instantiated and used elsewhere, or if it is not set
+            /// already in the mode of operation which is being instantiated
+            pub unsafe fn new(pin: i32) -> Self {
+                Self {
+                    pin,
+                    _p: PhantomData,
+                }
+            }
+        }
+
+        impl_peripheral_trait!(AnyOutputPin);
+
+        impl Pin for AnyOutputPin {
+            fn pin(&self) -> i32 {
+                self.pin
+            }
+        }
+
+        impl OutputPin for AnyOutputPin {}
+
+        impl From<AnyIOPin> for AnyOutputPin {
+            fn from(pin: AnyIOPin) -> Self {
+                unsafe { Self::new(pin.pin()) }
+            }
+        }
+
+        pub trait InputMode {
+            const RTC: bool;
+        }
+        pub trait OutputMode {
+            const RTC: bool;
+        }
+
+        pub struct Output;
+        pub struct Input;
+        pub struct InputOutput;
+
+        impl InputMode for Input {
+            const RTC: bool = false;
+        }
+
+        impl InputMode for InputOutput {
+            const RTC: bool = false;
+        }
+
+        impl OutputMode for Output {
+            const RTC: bool = false;
+        }
+
+        impl OutputMode for InputOutput {
+            const RTC: bool = false;
+        }
+
+        /// A driver for a GPIO pin.
+        ///
+        /// The driver can set the pin as a disconnected/disabled one, input, or output pin, or both or analog.
+        /// On some chips (i.e. esp32 and esp32s*), the driver can also set the pin in RTC IO mode.
+        /// Depending on the current operating mode, different sets of functions are available.
+        ///
+        /// The mode-setting depends on the capabilities of the pin as well, i.e. input-only pins cannot be set
+        /// into output or input-output mode.
+        pub struct PinDriver<'d, T: Pin, MODE> {
+            pin: PeripheralRef<'d, T>,
+            _mode: PhantomData<MODE>,
+        }
+
+        impl<'d, T: InputPin> PinDriver<'d, T, Input> {
+            /// Creates the driver for a pin in input state.
+            #[inline]
+            pub fn input(pin: impl Peripheral<P = T> + 'd) -> Result<Self> {
+                crate::into_ref!(pin);
+
+                Self {
+                    pin,
+                    _mode: PhantomData,
+                }
+                .into_input()
+            }
+        }
+
+        impl<'d, T: InputPin + OutputPin> PinDriver<'d, T, InputOutput> {
+            /// Creates the driver for a pin in input-output state.
+            #[inline]
+            pub fn input_output(pin: impl Peripheral<P = T> + 'd) -> Result<Self> {
+                crate::into_ref!(pin);
+
+                Self {
+                    pin,
+                    _mode: PhantomData,
+                }
+                .into_input_output()
+            }
+        }
+
+        impl<'d, T: OutputPin> PinDriver<'d, T, Output> {
+            /// Creates the driver for a pin in output state.
+            #[inline]
+            pub fn output(pin: impl Peripheral<P = T> + 'd) -> Result<Self> {
+                crate::into_ref!(pin);
+
+                Self {
+                    pin,
+                    _mode: PhantomData,
+                }
+                .into_output()
+            }
+        }
+
+        impl<'d, T: Pin, MODE> PinDriver<'d, T, MODE> {
+            /// Returns the pin number.
+            pub fn pin(&self) -> i32 {
+                self.pin.pin()
+            }
+
+            /// Put the pin into input mode.
+            #[inline]
+            pub fn into_input(self) -> Result<PinDriver<'d, T, Input>>
+            where
+                T: InputPin,
+            {
+                self.into_mode("input")
+            }
+
+            /// Put the pin into input + output mode.
+            #[inline]
+            pub fn into_input_output(self) -> Result<PinDriver<'d, T, InputOutput>>
+            where
+                T: InputPin + OutputPin,
+            {
+                self.into_mode("input_output")
+            }
+
+            /// Put the pin into output mode.
+            #[inline]
+            pub fn into_output(self) -> Result<PinDriver<'d, T, Output>>
+            where
+                T: OutputPin,
+            {
+                self.into_mode("output")
+            }
+
+            #[inline]
+            fn into_mode<M>(mut self, mode: &str) -> Result<PinDriver<'d, T, M>>
+            where
+                T: Pin,
+            {
+                let pin = unsafe { self.pin.clone_unchecked() };
+
+                drop(self);
+
+                if mode != "disabled" {
+                    // esp!(unsafe { gpio_set_direction(pin.pin(), mode) })?;
+                }
+
+                Ok(PinDriver {
+                    pin,
+                    _mode: PhantomData,
+                })
+            }
+
+            /// Toggle pin output
+            #[inline]
+            pub fn toggle(&mut self) -> Result<()>
+            where
+                MODE: OutputMode,
+            {
+                // Todo
+                Ok(())
+            }
+        }
+
+        unsafe impl<'d, T: Pin, MODE> Send for PinDriver<'d, T, MODE> {}
+
+        macro_rules! impl_input {
+            ($pxi:ident: $pin:expr) => {
+                $crate::traits::lesson_3::core::impl_peripheral!($pxi);
+
+                impl $crate::traits::lesson_3::gpio::Pin for $pxi {
+                    fn pin(&self) -> i32 {
+                        $pin
+                    }
+                }
+
+                impl InputPin for $pxi {}
+
+                impl From<$pxi> for AnyInputPin {
+                    fn from(pin: $pxi) -> Self {
+                        unsafe { Self::new(pin.pin()) }
+                    }
+                }
+            };
+        }
+
+        macro_rules! impl_input_output {
+            ($pxi:ident: $pin:expr) => {
+                $crate::traits::lesson_3::gpio::impl_input!($pxi: $pin);
+
+                impl OutputPin for $pxi {}
+
+                impl IOPin for $pxi {}
+
+                impl From<$pxi> for AnyOutputPin {
+                    fn from(pin: $pxi) -> Self {
+                        unsafe { Self::new(pin.pin()) }
+                    }
+                }
+
+                impl From<$pxi> for AnyIOPin {
+                    fn from(pin: $pxi) -> Self {
+                        unsafe { Self::new(pin.pin()) }
+                    }
+                }
+            };
+        }
+
+        macro_rules! pin {
+            ($pxi:ident: $pin:expr, Input) => {
+                $crate::traits::lesson_3::gpio::impl_input!($pxi: $pin);
+            };
+
+            ($pxi:ident: $pin:expr, IO) => {
+                $crate::traits::lesson_3::gpio::impl_input_output!($pxi: $pin);
+            };
+        }
+
+        #[allow(unused_imports)]
+        pub(crate) use impl_input;
+        #[allow(unused_imports)]
+        pub(crate) use impl_input_output;
+        #[allow(unused_imports)]
+        pub(crate) use pin;
+    }
+
+    pub fn run() -> Result<()> {
+        use gpio::*;
+        use std::ops::Deref;
+
+        gpio::pin!(Gpio0:0, IO);
+        gpio::pin!(Gpio34:34, Input);
+
+        unsafe {
+            let gpio0 = Gpio0::new();
+            let mut io_pin = gpio0.downgrade();
+
+            {
+                let mut pin_driver = PinDriver::input_output(&mut io_pin)?;
+
+                pin_driver.toggle()?;
+            }
+            // NOTE: by using a block here, the `pin_driver` is implicitly dropped when execution reaches the end of the block.  This allowes for the drowngraded pin to be used without clashing with the borrow-checker.
+        }
+
+        Ok(())
+    }
+}
+
+fn test_mut_t<T>(device: T, message: &str)
+where
+    T: ErrorType,
+{
+    info!("{}", message);
+}
+
+fn lesson_2() {
+    let device = RTCDevice(1);
+    test_mut_t::<RTCDevice>(device, "This is a standard use of `T: Trait`");
+
+    // This works with the "forwarding impl" for `&mut T`.  It is handy to note that `T: Trait`, doesn't automatically mean `&mut T: Trait`. You have to write a "forwarding impl" for that. These are fairly common. &mut has them for Iterator, Write, Display, Debug, and more, for example
+    let mut device = RTCDevice(1);
+    test_mut_t::<&mut RTCDevice>(&mut device, "Here we are using `&mut T: Trait`");
+}
+
+fn lesson_1_add_trait_bound_to_parameter() {
+    let device = Device::new(1);
+
+    // If we try to run `let resp = x(Box::new(device));`, notice that we have not satisfied the trait bound that is specified on `x`.
+    //
+    // error[E0277]: `Device` doesn't implement `std::fmt::Display`
+    //   --> src/lib/traits.rs:19:18
+    //    |
+    // 19 |     let resp = x(Box::new(device));
+    //    |                - ^^^^^^^^^^^^^^^^ `Device` cannot be formatted with the default formatter
+    //    |                |
+    //    |                required by a bound introduced by this call
+    //    |
+    //    = help: the trait `std::fmt::Display` is not implemented for `Device`
+    //    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+    // note: required by a bound in `x`
+    //   --> src/lib/traits.rs:4:22
+    //    |
+    // 4  | pub fn x(b: Box<impl Display + 'static>) -> Box<dyn Display> {
+    //    |                      ^^^^^^^ required by this bound in `x`
+    let resp = x(Box::new(device));
+}
+
+// https://github.com/dtolnay/erased-serde/blob/master/explanation/main.rs
+mod lesson_4 {
+    /////////////////////////////////////////////////////////////////////
+    // Suppose these are the real traits from Serde.
+
+    trait Querializer {}
+
+    trait Generic {
+        // Not object safe because of this generic method.
+        fn generic_fn<Q: Querializer>(&self, querializer: Q);
+    }
+
+    // Note: extra constraint `where T: Querializer` does not seem to be needed.
+    impl<'a, T: ?Sized> Querializer for &'a T {}
+
+    impl<'a, T: ?Sized> Generic for Box<T>
+    where
+        T: Generic,
+    {
+        fn generic_fn<Q: Querializer>(&self, querializer: Q) {
+            println!("impl<'a, T: ?Sized> Generic for Box<T>: calling generic_fn()");
+
+            (**self).generic_fn(querializer)
+        }
+    }
+
+    /////////////////////////////////////////////////////////////////////
+    // This is an object-safe equivalent that interoperates seamlessly.
+
+    trait ErasedGeneric {
+        fn erased_fn(&self, querializer: &dyn Querializer);
+    }
+
+    impl Generic for dyn ErasedGeneric {
+        // Depending on the trait method signatures and the upstream
+        // impls, could also implement for:
+        //
+        //   - &'a dyn ErasedGeneric
+        //   - &'a (dyn ErasedGeneric + Send)
+        //   - &'a (dyn ErasedGeneric + Sync)
+        //   - &'a (dyn ErasedGeneric + Send + Sync)
+        //   - Box<dyn ErasedGeneric>
+        //   - Box<dyn ErasedGeneric + Send>
+        //   - Box<dyn ErasedGeneric + Sync>
+        //   - Box<dyn ErasedGeneric + Send + Sync>
+        fn generic_fn<Q: Querializer>(&self, querializer: Q) {
+            println!("impl Generic for dyn ErasedGeneric: call self.erased_fn()");
+            self.erased_fn(&querializer)
+        }
+    }
+
+    impl<T> ErasedGeneric for T
+    where
+        T: Generic,
+    {
+        fn erased_fn(&self, querializer: &dyn Querializer) {
+            println!("erased_fn() caling self.generic_fn");
+            self.generic_fn(querializer)
+        }
+    }
+
+    pub fn run() {
+        struct T;
+        impl Querializer for T {}
+
+        #[derive(Debug)]
+        struct S {
+            size: usize,
+        }
+        impl Generic for S {
+            fn generic_fn<Q: Querializer>(&self, _querializer: Q) {
+                println!("querying the real S");
+            }
+        }
+
+        impl Generic for &S {
+            fn generic_fn<Q: Querializer>(&self, _querializer: Q) {
+                println!("querying the real &S");
+                let s = *self;
+
+                dbg!("{:#?}", s);
+            }
+        }
+
+        // Construct a trait object.
+        let trait_object: Box<dyn ErasedGeneric> = Box::new(S { size: 0 });
+
+        // Seamlessly invoke the generic method on the trait object.
+        //
+        // THIS LINE LOOKS LIKE MAGIC. We have a value of type trait
+        // object and we are invoking a generic method on it.
+        trait_object.generic_fn(T);
+
+        println!("");
+        let trait_object: Box<dyn ErasedGeneric> = Box::new(&S { size: 0 });
+        trait_object.generic_fn(T);
+    }
+}
+
+mod lesson_5 {
+    use std::any::Any;
+    /////////////////////////////////////////////////////////////////////
+    // Suppose these are the real traits from Serde.
+
+    trait Task {}
+
+    trait Generic {
+        // Not object safe because of this generic method.
+        fn generic_fn<Q: Task>(&self, task: Q);
+    }
+
+    // Note: extra constraint `where T: Task` does not seem to be needed.
+    impl<'a, T: ?Sized> Task for &'a T {}
+
+    impl<'a, T: ?Sized> Generic for Box<T>
+    where
+        T: Generic,
+    {
+        fn generic_fn<Q: Task>(&self, task: Q) {
+            println!("impl<'a, T: ?Sized> Generic for Box<T>: calling generic_fn()");
+
+            (**self).generic_fn(task)
+        }
+    }
+
+    /////////////////////////////////////////////////////////////////////
+    // This is an object-safe equivalent that interoperates seamlessly.
+
+    trait AsAny {
+        fn as_any(&self) -> &dyn Any;
+    }
+
+    trait ErasedGeneric {
+        fn erased_fn(&self, task: &dyn Task);
+
+        fn as_any(&self) -> &dyn Any;
+    }
+
+    impl Generic for dyn ErasedGeneric {
+        // Depending on the trait method signatures and the upstream
+        // impls, could also implement for:
+        //
+        //   - &'a dyn ErasedGeneric
+        //   - &'a (dyn ErasedGeneric + Send)
+        //   - &'a (dyn ErasedGeneric + Sync)
+        //   - &'a (dyn ErasedGeneric + Send + Sync)
+        //   - Box<dyn ErasedGeneric>
+        //   - Box<dyn ErasedGeneric + Send>
+        //   - Box<dyn ErasedGeneric + Sync>
+        //   - Box<dyn ErasedGeneric + Send + Sync>
+        fn generic_fn<Q: Task>(&self, task: Q) {
+            println!("impl Generic for dyn ErasedGeneric: call self.erased_fn()");
+            self.erased_fn(&task)
+        }
+    }
+
+    impl<T> ErasedGeneric for T
+    where
+        T: Generic + 'static,
+    {
+        fn erased_fn(&self, task: &dyn Task) {
+            println!("erased_fn() caling self.generic_fn");
+            self.generic_fn(task)
+        }
+
+        fn as_any(&self) -> &dyn Any {
+            self
+        }
+    }
+
+    pub fn run() {
+        #[derive(Debug)]
+        struct T;
+        impl Task for T {}
+
+        #[derive(Debug)]
+        struct S {
+            size: usize,
+        }
+        impl Generic for S {
+            fn generic_fn<Q: Task>(&self, _task: Q) {
+                println!("querying the real S");
+
+                let s = self;
+
+                dbg!("{:#?}", s);
+            }
+        }
+
+        #[derive(Debug)]
+        struct M {
+            size: usize,
+        }
+        impl Generic for M {
+            fn generic_fn<Q: Task>(&self, _task: Q) {
+                println!("querying the real M");
+
+                let s = self;
+
+                dbg!("{:#?}", s);
+            }
+        }
+
+        struct Tasks {
+            tasks: Vec<Box<dyn ErasedGeneric>>,
+        }
+
+        // Construct a trait object.
+        let mut tasks: Vec<Box<dyn ErasedGeneric>> = vec![];
+        let trait_object1: Box<dyn ErasedGeneric> = Box::new(S { size: 0 });
+        let trait_object2: Box<dyn ErasedGeneric> = Box::new(M { size: 0 });
+        tasks.push(trait_object1);
+        tasks.push(trait_object2);
+
+        for (index, task) in tasks.iter().enumerate() {
+            // task.generic_fn(T);
+
+            if let Some(inner) = task.as_ref().as_any().downcast_ref::<S>() {
+                println!("Downcast index {index} of type S: {:#?}", inner);
+            }
+
+            if let Some(inner) = task.as_ref().as_any().downcast_ref::<M>() {
+                println!("Downcast index {index} of type M: {:#?}", inner);
+            }
+        }
+    }
+}
+
+mod lesson6 {
+    use axum::{
+        body::Body,
+        extract::{FromRequest, FromRequestParts, State},
+        handler::{HandlerService as OtherHandlerService, Layered as OtherLayered},
+        response::IntoResponse,
+        routing::get,
+        Router,
+    };
+    use futures::Future;
+    use hyper::body::Buf;
+    use hyper::http::{Request, Response};
+    use std::{convert::Infallible, fmt, marker::PhantomData, pin::Pin};
+    use tower_layer::Layer;
+    use tower_service::Service;
+
+    pub struct Layered<L, H, T, S, B, B2> {
+        pub layer: L,
+        pub handler: H,
+        pub _marker: PhantomData<fn() -> (T, S, B, B2)>,
+    }
+
+    pub struct HandlerService<H, T, S, B> {
+        pub handler: H,
+        pub state: S,
+        pub _marker: PhantomData<fn() -> (T, B)>,
+    }
+
+    pub trait Handler<T, S>: Clone + Send + Sized + 'static {
+        /// The type of future calling this handler returns.
+        type Future: Future<Output = Response<Self::RespType>> + Send + 'static;
+
+        type RespType;
+
+        /// Call the handler with the given request.
+        fn call(self, req: Request<Self::RespType>, state: S) -> Self::Future;
+
+        /// Apply a [`tower::Layer`] to the handler.
+        fn layer<L, B, B2>(self, layer: L) -> Layered<L, Self, T, S, B, B2>
+        where
+            L: Layer<HandlerService<Self, T, S, B>> + Clone,
+            L::Service: Service<Request<Self::RespType>>,
+        {
+            Layered {
+                layer,
+                handler: self,
+                _marker: PhantomData,
+            }
+        }
+
+        /// Convert the handler into a [`Service`] by providing the state
+        fn with_state<B>(
+            self,
+            state: S,
+            _: PhantomData<fn() -> (T, B)>,
+        ) -> HandlerService<Self, T, S, B> {
+            // NOTE calling `new` is private
+            // HandlerService::new(self, state)
+            HandlerService {
+                handler: self,
+                state,
+                _marker: PhantomData,
+            }
+        }
+    }
+
+    impl<F, Fut, Res, S> Handler<((),), S> for F
+    where
+        F: FnOnce() -> Fut + Clone + Send + 'static,
+        Fut: Future<Output = Res> + Send,
+        Res: IntoResponse,
+    {
+        type Future = Pin<Box<dyn Future<Output = Response<Self::RespType>> + Send>>;
+        type RespType = ();
+
+        fn call(self, _req: Request<Self::RespType>, _state: S) -> Self::Future {
+            Box::pin(async move {
+                let real_resp = self().await.into_response();
+
+                let response = Response::builder()
+                    .status(200)
+                    .header("X-Custom-Foo", "Bar")
+                    .body(())
+                    .unwrap();
+
+                response
+            })
+        }
+    }
+
+    pub fn run() {
+        // NOTE this breaks as we clash with existing expansion in axum.
+        // let app = Router::new().route("/", get(root));
+        //
+        // 403  | top_level_handler_fn!(get, GET);
+        //      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `get`
+    }
+
+    pub fn root() {
+        ()
+    }
+}
+
+mod lesson7 {
+    use super::*;
+
+    // Each caller needs to care about the generic `F` and propagate this type up.
+    // Also anyone using `Wrapper` needs to generic and name the type of `F`.
+    // pub struct Wrapper<F: Fn()> {
+    //     f: F,
+    // }
+
+    // This leads to a cleaner interface
+    pub struct Wrapper {
+        f: Box<dyn Fn()>,
+    }
+
+    // Either the following
+    //
+    // trait X {
+    //     fn foo(&self, f: impl Fn());
+    // }
+    //
+    // or
+    //
+    // trait X {
+    //     fn foo<F: Fn()>(&self, f: F);
+    // }
+    //
+    // fn quox(x: &dyn X) {}
+    //
+    // will not work as the trait needs to be object safe.
+
+    trait X {
+        fn foo(&self, f: ClosureType) -> u8;
+    }
+    // Now, there is only a single 'foo' in the V-table.
+
+    fn quox(x: &dyn X) {}
+
+    pub struct Entity {}
+
+    impl X for Entity {
+        fn foo(&self, f: ClosureType) -> u8 {
+            let x = (*f)();
+
+            x
+        }
+    }
+
+    pub fn do_closure() -> u8 {
+        10
+    }
+
+    pub type ClosureType<'a> = &'a dyn Fn() -> u8;
+
+    pub fn run() {
+        let e = Entity {};
+
+        let x: u8 = 10;
+        let c = move || x * x;
+        let resp = e.foo(&c);
+        let resp2 = e.foo(&do_closure);
+
+        info!("lesson 7: resp: {}", resp);
+        info!("lesson 7: resp2: {}", resp2);
+    }
+}
+
+pub mod lesson8 {
+    mod error {
+        //! Error types.
+
+        use std::error::Error as StdError;
+        use std::fmt;
+        use std::io::Error as IoError;
+        use std::net::TcpStream;
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        use std::net::TcpStream;
+        use std::result;
+        use std::str::Utf8Error;
+
+        use base64::DecodeError;
+        use bufstream::IntoInnerError as BufError;
+        use imap_proto::{types::ResponseCode, Response};
+        #[cfg(feature = "native-tls")]
+        use native_tls::Error as TlsError;
+        #[cfg(feature = "native-tls")]
+        use native_tls::HandshakeError as TlsHandshakeError;
+        use rustls_connector::HandshakeError;
+        #[cfg(feature = "rustls-tls")]
+        use rustls_connector::HandshakeError as RustlsHandshakeError;
+
+        /// A convenience wrapper around `Result` for `imap::Error`.
+        pub type Result<T> = result::Result<T, Error>;
+
+        /// A BAD response from the server, which indicates an error message from the server.
+        #[derive(Debug)]
+        #[non_exhaustive]
+        pub struct Bad {
+            /// Human-redable message included with the Bad response.
+            pub information: String,
+            /// A more specific error status code included with the Bad response.
+            pub code: Option<ResponseCode<'static>>,
+        }
+
+        impl fmt::Display for Bad {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}", self.information)
+            }
+        }
+
+        /// A NO response from the server, which indicates an operational error message from the server.
+        #[derive(Debug)]
+        #[non_exhaustive]
+        pub struct No {
+            /// Human-redable message included with the NO response.
+            pub information: String,
+            /// A more specific error status code included with the NO response.
+            pub code: Option<ResponseCode<'static>>,
+        }
+
+        impl fmt::Display for No {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}", self.information)
+            }
+        }
+
+        /// A BYE response from the server, which indicates it is going to hang up on us.
+        #[derive(Debug)]
+        #[non_exhaustive]
+        pub struct Bye {
+            /// Human-redable message included with the response.
+            pub information: String,
+            /// A more specific error status code included with the response.
+            pub code: Option<ResponseCode<'static>>,
+        }
+
+        impl fmt::Display for Bye {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}", self.information)
+            }
+        }
+        /// A set of errors that can occur in the IMAP client
+        #[derive(Debug)]
+        #[non_exhaustive]
+        pub enum Error {
+            /// An `io::Error` that occurred while trying to read or write to a network stream.
+            Io(IoError),
+            /// An error from the `rustls` library during the TLS handshake.
+            #[cfg(feature = "rustls-tls")]
+            RustlsHandshake(RustlsHandshakeError<TcpStream>),
+            RustlsHandshakeErr(HandshakeError<TcpStream>),
+
+            /// An error from the `native_tls` library during the TLS handshake.
+            #[cfg(feature = "native-tls")]
+            TlsHandshake(TlsHandshakeError<TcpStream>),
+            /// An error from the `native_tls` library while managing the socket.
+            #[cfg(feature = "native-tls")]
+            Tls(TlsError),
+            /// A BAD response from the IMAP server.
+            Bad(Bad),
+            /// A NO response from the IMAP server.
+            No(No),
+            /// A BYE response from the IMAP server.
+            Bye(Bye),
+            /// The connection was terminated unexpectedly.
+            ConnectionLost,
+            /// Error parsing a server response.
+            Parse(ParseError),
+            /// Command inputs were not valid [IMAP
+            /// strings](https://tools.ietf.org/html/rfc3501#section-4.3).
+            Validate(ValidateError),
+            /// Error appending an e-mail.
+            Append,
+            /// An unexpected response was received. This could be a response from a command,
+            /// or an unsolicited response that could not be converted into a local type in
+            /// [`UnsolicitedResponse`](crate::types::UnsolicitedResponse).
+            Unexpected(Response<'static>),
+            /// In response to a STATUS command, the server sent OK without actually sending any STATUS
+            /// responses first.
+            MissingStatusResponse,
+            /// StartTls is not available on the server
+            StartTlsNotAvailable,
+            #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+            /// Returns when Tls is not configured
+            TlsNotConfigured,
+        }
+
+        impl From<IoError> for Error {
+            fn from(err: IoError) -> Error {
+                Error::Io(err)
+            }
+        }
+
+        impl From<ParseError> for Error {
+            fn from(err: ParseError) -> Error {
+                Error::Parse(err)
+            }
+        }
+
+        impl<T> From<BufError<T>> for Error {
+            fn from(err: BufError<T>) -> Error {
+                Error::Io(err.into())
+            }
+        }
+
+        #[cfg(feature = "rustls-tls")]
+        impl From<RustlsHandshakeError<TcpStream>> for Error {
+            fn from(err: RustlsHandshakeError<TcpStream>) -> Error {
+                Error::RustlsHandshake(err)
+            }
+        }
+
+        #[cfg(feature = "native-tls")]
+        impl From<TlsHandshakeError<TcpStream>> for Error {
+            fn from(err: TlsHandshakeError<TcpStream>) -> Error {
+                Error::TlsHandshake(err)
+            }
+        }
+
+        impl From<HandshakeError<TcpStream>> for Error {
+            fn from(err: HandshakeError<TcpStream>) -> Error {
+                Error::RustlsHandshakeErr(err)
+            }
+        }
+
+        #[cfg(feature = "native-tls")]
+        impl From<TlsError> for Error {
+            fn from(err: TlsError) -> Error {
+                Error::Tls(err)
+            }
+        }
+
+        impl<'a> From<Response<'a>> for Error {
+            fn from(err: Response<'a>) -> Error {
+                Error::Unexpected(err.into_owned())
+            }
+        }
+
+        impl fmt::Display for Error {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                match *self {
+                    Error::Io(ref e) => fmt::Display::fmt(e, f),
+                    #[cfg(feature = "rustls-tls")]
+                    Error::RustlsHandshake(ref e) => fmt::Display::fmt(e, f),
+                    Error::RustlsHandshakeErr(ref e) => fmt::Display::fmt(e, f),
+                    #[cfg(feature = "native-tls")]
+                    Error::Tls(ref e) => fmt::Display::fmt(e, f),
+                    #[cfg(feature = "native-tls")]
+                    Error::TlsHandshake(ref e) => fmt::Display::fmt(e, f),
+                    Error::Validate(ref e) => fmt::Display::fmt(e, f),
+                    Error::Parse(ref e) => fmt::Display::fmt(e, f),
+                    Error::No(ref data) => write!(f, "No Response: {}", data),
+                    Error::Bad(ref data) => write!(f, "Bad Response: {}", data),
+                    Error::Bye(ref data) => write!(f, "Bye Response: {}", data),
+                    Error::ConnectionLost => f.write_str("Connection Lost"),
+                    Error::Append => f.write_str("Could not append mail to mailbox"),
+                    Error::Unexpected(ref r) => write!(f, "Unexpected Response: {:?}", r),
+                    Error::MissingStatusResponse => write!(f, "Missing STATUS Response"),
+                    Error::StartTlsNotAvailable => {
+                        write!(f, "StartTls is not available on the server")
+                    }
+                    #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+                    Error::TlsNotConfigured => write!(f, "No Tls feature is available"),
+                }
+            }
+        }
+
+        impl StdError for Error {
+            #[allow(deprecated)]
+            fn description(&self) -> &str {
+                match *self {
+                    Error::Io(ref e) => e.description(),
+                    #[cfg(feature = "rustls-tls")]
+                    Error::RustlsHandshake(ref e) => e.description(),
+                    Error::RustlsHandshakeErr(ref e) => e.description(),
+                    #[cfg(feature = "native-tls")]
+                    Error::Tls(ref e) => e.description(),
+                    #[cfg(feature = "native-tls")]
+                    Error::TlsHandshake(ref e) => e.description(),
+                    Error::Parse(ref e) => e.description(),
+                    Error::Validate(ref e) => e.description(),
+                    Error::Bad(_) => "Bad Response",
+                    Error::No(_) => "No Response",
+                    Error::Bye(_) => "Bye Response",
+                    Error::ConnectionLost => "Connection lost",
+                    Error::Append => "Could not append mail to mailbox",
+                    Error::Unexpected(_) => "Unexpected Response",
+                    Error::MissingStatusResponse => "Missing STATUS Response",
+                    Error::StartTlsNotAvailable => "StartTls is not available on the server",
+                    #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+                    Error::TlsNotConfigured => "No Tls feature is available",
+                }
+            }
+
+            fn cause(&self) -> Option<&dyn StdError> {
+                match *self {
+                    Error::Io(ref e) => Some(e),
+                    #[cfg(feature = "rustls-tls")]
+                    Error::RustlsHandshake(ref e) => Some(e),
+                    Error::RustlsHandshakeErr(ref e) => Some(e),
+                    #[cfg(feature = "native-tls")]
+                    Error::Tls(ref e) => Some(e),
+                    #[cfg(feature = "native-tls")]
+                    Error::TlsHandshake(ref e) => Some(e),
+                    Error::Parse(ParseError::DataNotUtf8(_, ref e)) => Some(e),
+                    _ => None,
+                }
+            }
+        }
+
+        /// An error occured while trying to parse a server response.
+        #[derive(Debug)]
+        pub enum ParseError {
+            /// Indicates an error parsing the status response. Such as OK, NO, and BAD.
+            Invalid(Vec<u8>),
+            /// The client could not find or decode the server's authentication challenge.
+            Authentication(String, Option<DecodeError>),
+            /// The client received data that was not UTF-8 encoded.
+            DataNotUtf8(Vec<u8>, Utf8Error),
+        }
+
+        impl fmt::Display for ParseError {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                match *self {
+                    ParseError::Invalid(_) => f.write_str("Unable to parse status response"),
+                    ParseError::Authentication(_, _) => {
+                        f.write_str("Unable to parse authentication response")
+                    }
+                    ParseError::DataNotUtf8(_, _) => {
+                        f.write_str("Unable to parse data as UTF-8 text")
+                    }
+                }
+            }
+        }
+
+        impl StdError for ParseError {
+            fn description(&self) -> &str {
+                match *self {
+                    ParseError::Invalid(_) => "Unable to parse status response",
+                    ParseError::Authentication(_, _) => "Unable to parse authentication response",
+                    ParseError::DataNotUtf8(_, _) => "Unable to parse data as UTF-8 text",
+                }
+            }
+
+            fn cause(&self) -> Option<&dyn StdError> {
+                match *self {
+                    ParseError::Authentication(_, Some(ref e)) => Some(e),
+                    _ => None,
+                }
+            }
+        }
+
+        /// An [invalid character](https://tools.ietf.org/html/rfc3501#section-4.3) was found in a command
+        /// argument.
+        #[derive(Debug)]
+        pub struct ValidateError {
+            /// the synopsis of the invalid command
+            pub(crate) command_synopsis: String,
+            /// the name of the invalid argument
+            pub(crate) argument: String,
+            /// the invalid character contained in the argument
+            pub(crate) offending_char: char,
+        }
+
+        impl fmt::Display for ValidateError {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                // print character in debug form because invalid ones are often whitespaces
+                write!(
+                    f,
+                    "Invalid character {:?} in argument '{}' of command '{}'",
+                    self.offending_char, self.argument, self.command_synopsis
+                )
+            }
+        }
+
+        impl StdError for ValidateError {
+            fn description(&self) -> &str {
+                "Invalid character in command argument"
+            }
+
+            fn cause(&self) -> Option<&dyn StdError> {
+                None
+            }
+        }
+
+        #[cfg(test)]
+        mod tests {
+            use super::*;
+
+            #[test]
+            fn validate_error_display() {
+                assert_eq!(
+                    ValidateError {
+                        command_synopsis: "COMMAND arg1 arg2".to_owned(),
+                        argument: "arg2".to_string(),
+                        offending_char: '\n'
+                    }
+                    .to_string(),
+                    "Invalid character '\\n' in argument 'arg2' of command 'COMMAND arg1 arg2'"
+                );
+            }
+        }
+    }
+
+    pub mod client {
+        use crate::traits::lesson8::error::{Error, Result};
+        use bufstream::BufStream;
+        use std::{
+            io::{Read, Write},
+            ops::{Deref, DerefMut},
+        };
+
+        const INITIAL_TAG: u32 = 0;
+        const CR: u8 = 0x0d;
+        const LF: u8 = 0x0a;
+
+        /// An (unauthenticated) handle to talk to an IMAP server. This is what you get when first
+        /// connecting. A succesfull call to [`Client::login`] or [`Client::authenticate`] will return a
+        /// [`Session`] instance that provides the usual IMAP methods.
+        // Both `Client` and `Session` deref to [`Connection`](struct.Connection.html), the underlying
+        // primitives type.
+        #[derive(Debug)]
+        pub struct Client<T: Read + Write> {
+            conn: Connection<T>,
+        }
+
+        /// The underlying primitives type. Both `Client`(unauthenticated) and `Session`(after succesful
+        /// login) use a `Connection` internally for the TCP stream primitives.
+        #[derive(Debug)]
+        #[doc(hidden)]
+        pub struct Connection<T: Read + Write> {
+            pub(crate) stream: BufStream<T>,
+            tag: u32,
+
+            /// Enable debug mode for this connection so that all client-server interactions are printed to
+            /// `STDERR`.
+            pub debug: bool,
+
+            /// Tracks if we have read a greeting.
+            pub greeting_read: bool,
+        }
+
+        // `Deref` instances are so we can make use of the same underlying primitives in `Client` and
+        // `Session`
+        impl<T: Read + Write> Deref for Client<T> {
+            type Target = Connection<T>;
+
+            fn deref(&self) -> &Connection<T> {
+                &self.conn
+            }
+        }
+
+        impl<T: Read + Write> DerefMut for Client<T> {
+            fn deref_mut(&mut self) -> &mut Connection<T> {
+                &mut self.conn
+            }
+        }
+
+        impl<T: Read + Write> Client<T> {
+            /// Creates a new client over the given stream.
+            ///
+            /// This method primarily exists for writing tests that mock the underlying transport,
+            /// but can also be used to support IMAP over custom tunnels. If you do not need to do
+            /// that, then it is simpler to use the [`ClientBuilder`](crate::ClientBuilder) to get
+            /// a new client.
+            ///
+            /// For an example, see `examples/timeout.rs` which uses a custom timeout on the
+            /// tcp stream.
+            ///
+            /// **Note:** In case you do need to use `Client::new` instead of the `ClientBuilder`
+            /// you will need to listen for the IMAP protocol server greeting before authenticating:
+            ///
+            /// ```rust,no_run
+            /// # use tutorials::traits::lesson8::client::Client;
+            /// # use std::io;
+            /// # use std::net::TcpStream;
+            /// # {} #[cfg(feature = "native-tls")]
+            /// # fn main() {
+            /// # let server = "imap.example.com";
+            /// # let username = "";
+            /// # let password = "";
+            /// # let tcp = TcpStream::connect((server, 993)).unwrap();
+            /// # use native_tls::TlsConnector;
+            /// # let ssl_connector = TlsConnector::builder().build().unwrap();
+            /// # let tls = TlsConnector::connect(&ssl_connector, server.as_ref(), tcp).unwrap();
+            /// let mut client = Client::new(tls);
+            /// client.read_greeting().unwrap();
+            /// let session = client.login(username, password).unwrap();
+            /// # }
+            /// ```
+            pub fn new(stream: T) -> Client<T> {
+                Client {
+                    conn: Connection {
+                        stream: BufStream::new(stream),
+                        tag: INITIAL_TAG,
+                        debug: false,
+                        greeting_read: false,
+                    },
+                }
+            }
+        }
+
+        impl<T: Read + Write> Connection<T> {
+            /// Read the greeting from the connection. Needs to be done after `connect`ing.
+            ///
+            /// Panics if called more than once on the same `Connection`.
+            pub fn read_greeting(&mut self) -> Result<Vec<u8>> {
+                assert!(!self.greeting_read, "Greeting can only be read once");
+
+                let mut v = Vec::new();
+                self.readline(&mut v)?;
+                self.greeting_read = true;
+
+                Ok(v)
+            }
+
+            pub(crate) fn readline(&mut self, into: &mut Vec<u8>) -> Result<usize> {
+                use std::io::BufRead;
+                let read = self.stream.read_until(LF, into)?;
+                if read == 0 {
+                    return Err(Error::ConnectionLost);
+                }
+
+                if self.debug {
+                    // Remove CRLF
+                    let len = into.len();
+                    let line = &into[(len - read)..(len - 2)];
+                    eprintln!("S: {}", String::from_utf8_lossy(line));
+                }
+
+                Ok(read)
+            }
+        }
+    }
+
+    mod conn {
+        use super::*;
+        use crate::traits::lesson8::extensions::idle::SetReadTimeout;
+        use std::fmt::{Debug, Formatter};
+        use std::io::{Read, Write};
+
+        /// Imap connection trait of a read/write stream
+        pub trait ImapConnection: Read + Write + Send + SetReadTimeout + private::Sealed {}
+
+        impl<T> ImapConnection for T where T: Read + Write + Send + SetReadTimeout {}
+
+        impl Debug for dyn ImapConnection {
+            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+                write!(f, "Imap connection")
+            }
+        }
+
+        /// A boxed connection type
+        pub type Connection = Box<dyn ImapConnection>;
+
+        mod private {
+            use super::{Read, SetReadTimeout, Write};
+
+            pub trait Sealed {}
+
+            impl<T> Sealed for T where T: Read + Write + SetReadTimeout {}
+        }
+    }
+
+    pub mod extensions {
+        pub mod idle {
+            use rustls::{ClientConnection, StreamOwned};
+
+            use crate::traits::lesson8::{
+                conn::Connection,
+                error::{Error, Result},
+            };
+            use std::{net::TcpStream, ops::DerefMut, time::Duration};
+
+            /// Must be implemented for a transport in order for a `Session` to use IDLE.
+            pub trait SetReadTimeout {
+                /// Set the timeout for subsequent reads to the given one.
+                ///
+                /// If `timeout` is `None`, the read timeout should be removed.
+                ///
+                /// See also `std::net::TcpStream::set_read_timeout`.
+                fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()>;
+            }
+
+            impl<'a> SetReadTimeout for Connection {
+                fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
+                    self.deref_mut().set_read_timeout(timeout)
+                }
+            }
+
+            impl<'a> SetReadTimeout for TcpStream {
+                fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
+                    TcpStream::set_read_timeout(self, timeout).map_err(Error::Io)
+                }
+            }
+        }
+    }
+
+    use self::{client::Client, extensions::idle::SetReadTimeout};
+    use conn::{Connection, ImapConnection};
+    use error::{Error, Result};
+    use std::io::{Read, Write};
+    use std::net::TcpStream;
+
+    /// The connection mode we are going to use
+    #[derive(Clone, Debug, PartialEq, Eq)]
+    pub enum ConnectionMode {
+        /// Automatically detect what connection mode should be used.
+        /// This will use TLS if the port is 993, and StartTLls if the server says it's available.
+        /// If only Plaintext is available it will error out.
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        AutoTls,
+        /// Automatically detect what connection mode should be used.
+        /// This will use TLS if the port is 993, and StartTLls if the server says it's available.
+        /// Finally it will fallback to Plaintext
+        Auto,
+        /// A plain unencrypted Tcp connection
+        Plaintext,
+        /// an encrypted TLS connection
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        Tls,
+        /// a start tls connection
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        StartTls,
+    }
+
+    /// The tls backend to use, either explicit or auto (default)
+    #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+    #[derive(Clone, Debug, Eq, PartialEq)]
+    #[non_exhaustive]
+    pub enum TlsKind {
+        /// Use the NativeTLS backend
+        #[cfg(feature = "native-tls")]
+        Native,
+        /// Use the Rustls backend
+        #[cfg(feature = "rustls-tls")]
+        Rust,
+        /// Use whatever backend is available (uses rustls if both are available)
+        Any,
+    }
+
+    #[derive(Clone)]
+    pub struct ClientBuilder<D>
+    where
+        D: AsRef<str>,
+    {
+        domain: D,
+        port: u16,
+        mode: ConnectionMode,
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        tls_kind: TlsKind,
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        skip_tls_verify: bool,
+    }
+
+    impl<D> ClientBuilder<D>
+    where
+        D: AsRef<str>,
+    {
+        /// Make a new `ClientBuilder` using the given domain and port.
+        pub fn new(domain: D, port: u16) -> Self {
+            ClientBuilder {
+                domain,
+                port,
+                #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                mode: ConnectionMode::AutoTls,
+                #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+                mode: ConnectionMode::Auto,
+                #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                tls_kind: TlsKind::Any,
+                #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                skip_tls_verify: false,
+            }
+        }
+
+        /// Sets the Connection mode to use for this connection
+        pub fn mode(&mut self, mode: ConnectionMode) -> &mut Self {
+            self.mode = mode;
+            self
+        }
+
+        /// Sets the TLS backend to use for this connection.
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        pub fn tls_kind(&mut self, kind: TlsKind) -> &mut Self {
+            self.tls_kind = kind;
+            self
+        }
+
+        /// Controls the use of certificate validation.
+        ///
+        /// Defaults to `false`.
+        ///
+        /// # Warning
+        ///
+        /// You should only use this as a last resort as it allows another server to impersonate the
+        /// server you think you're talking to, which would include being able to receive your
+        /// credentials.
+        ///
+        /// See [`native_tls::TlsConnectorBuilder::danger_accept_invalid_certs`],
+        /// [`native_tls::TlsConnectorBuilder::danger_accept_invalid_hostnames`],
+        /// [`rustls::ClientConfig::dangerous`]
+        #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+        pub fn danger_skip_tls_verify(&mut self, skip_tls_verify: bool) -> &mut Self {
+            self.skip_tls_verify = skip_tls_verify;
+            self
+        }
+
+        /// Make a [`Client`] using the configuration.
+        ///
+        /// ```no_run
+        /// # use tutorials::traits::lesson8::ClientBuilder;
+        /// # {} #[cfg(feature = "rustls-tls")]
+        /// # fn main() -> Result<(), imap::Error> {
+        /// let client = ClientBuilder::new("imap.example.com", 143)
+        ///     .starttls().connect()?;
+        /// # Ok(())
+        /// # }
+        /// ```
+        pub fn connect(&self) -> Result<Client<Connection>> {
+            #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+            return self.connect_with(|_domain, tcp| self.build_tls_connection(tcp));
+            #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+            return self.connect_with(|_domain, _tcp| -> Result<Connection> {
+                return Err(Error::TlsNotConfigured);
+            });
+        }
+
+        /// Make a [`Client`] using a custom initialization. This function is intended
+        /// to be used if your TLS setup requires custom work such as adding private CAs
+        /// or other specific TLS parameters.
+        ///
+        /// Note, if the connection does not end up as TLS, handshake will not be called.
+        /// This can happen if connection mode is set to Tcp, or the server does not support starttls.
+        ///
+        /// The `handshake` argument should accept two parameters:
+        ///
+        /// - domain: [`&str`]
+        /// - tcp: [`TcpStream`]
+        ///
+        /// and yield a `Result<C>` where `C` is `Read + Write + Send + SetReadTimeout + 'static,`.
+        /// It should only perform TLS initialization over the given `tcp` socket and return the
+        /// encrypted stream object, such as a [`native_tls::TlsStream`] or a
+        /// [`rustls_connector::TlsStream`].
+        ///
+        /// If the caller is using `STARTTLS` and previously called [`starttls`](Self::starttls)
+        /// then the `tcp` socket given to the `handshake` function will be connected and will
+        /// have initiated the `STARTTLS` handshake.
+        ///
+        /// ```no_run
+        /// # use tutorials::traits::lesson8::ClientBuilder;
+        /// # use rustls_connector::RustlsConnector;
+        /// # {} #[cfg(feature = "rustls-tls")]
+        /// # fn main() -> Result<(), imap::Error> {
+        /// let client = ClientBuilder::new("imap.example.com", 143)
+        ///     .starttls()
+        ///     .connect_with(|domain, tcp| {
+        ///         let ssl_conn = RustlsConnector::new_with_native_certs()?;
+        ///         Ok(ssl_conn.connect(domain, tcp)?)
+        ///     })?;
+        /// # Ok(())
+        /// # }
+        /// ```
+        #[allow(unused_variables)]
+        pub fn connect_with<F, C>(&self, handshake: F) -> Result<Client<Connection>>
+        where
+            F: FnOnce(&str, TcpStream) -> Result<C>,
+            C: Read + Write + Send + SetReadTimeout + 'static,
+        {
+            #[allow(unused_mut)]
+            let mut greeting_read = false;
+            let tcp = TcpStream::connect((self.domain.as_ref(), self.port))?;
+
+            let stream: Connection = match self.mode {
+                #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                ConnectionMode::AutoTls => {
+                    #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                    if self.port == 993 {
+                        Box::new(handshake(self.domain.as_ref(), tcp)?)
+                    } else {
+                        let (stream, upgraded) = self.upgrade_tls(Client::new(tcp), handshake)?;
+                        greeting_read = true;
+
+                        if !upgraded {
+                            Err(Error::StartTlsNotAvailable)?
+                        }
+                        stream
+                    }
+                    #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+                    Err(Error::StartTlsNotAvailable)?
+                }
+                ConnectionMode::Auto => {
+                    #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                    if self.port == 993 {
+                        Box::new(handshake(self.domain.as_ref(), tcp)?)
+                    } else {
+                        let (stream, _upgraded) = self.upgrade_tls(Client::new(tcp), handshake)?;
+                        greeting_read = true;
+
+                        stream
+                    }
+                    #[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
+                    Box::new(tcp)
+                }
+                ConnectionMode::Plaintext => Box::new(tcp),
+                #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                ConnectionMode::StartTls => {
+                    let (stream, upgraded) = self.upgrade_tls(Client::new(tcp), handshake)?;
+                    greeting_read = true;
+
+                    if !upgraded {
+                        Err(Error::StartTlsNotAvailable)?
+                    }
+                    stream
+                }
+                #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
+                ConnectionMode::Tls => Box::new(handshake(self.domain.as_ref(), tcp)?),
+            };
+
+            let mut client = Client::new(stream);
+            if !greeting_read {
+                client.read_greeting()?;
+            } else {
+                client.greeting_read = true;
+            }
+
+            Ok(client)
+        }
+    }
+
+    pub fn run() -> Result<()> {
+        let _client = ClientBuilder::new("imap.example.com", 143).connect_with(|domain, tcp| {
+            let ssl_conn = rustls_connector::RustlsConnector::new_with_native_certs()?;
+            Ok::<TcpStream, Error>(ssl_conn.connect(domain, tcp)?.sock)
+        })?;
+
+        Ok(())
+    }
+}
+
+mod lesson9 {
+    use std::error::Error;
+    use std::result::Result;
+
+    pub fn run() -> Result<(), &'static dyn Error> {
+        Ok(())
+    }
+}
+
+/// Nothing to do with Traits, needs to be stashed somewhere else.
+mod lesson10 {
+    use std::sync::Arc;
+
+    #[derive(Debug, Clone)]
+    struct Entity {
+        counter: Arc<Box<u8>>,
+    }
+
+    impl Entity {
+        pub fn new() -> Self {
+            Self {
+                counter: Arc::new(Box::new(0)),
+            }
+        }
+    }
+
+    pub fn run() {
+        let new_box = Entity::new();
+
+        let static_ref: &'static mut u8 = Box::leak(Box::new(**new_box.counter));
+        assert_eq!(static_ref, &0);
+
+        *static_ref = 2;
+        assert_eq!(static_ref, &2);
+
+        let counter = **new_box.counter;
+        assert_eq!(counter, 0);
+    }
+}
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..118c66d
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1 @@
+pub mod generate;
\ No newline at end of file
diff --git a/src/utils/generate.rs b/src/utils/generate.rs
new file mode 100644
index 0000000..72ab30f
--- /dev/null
+++ b/src/utils/generate.rs
@@ -0,0 +1,55 @@
+//! The MIT License (MIT)
+//!
+//! Copyright (c) Michael de Silva (https://desilva.io/about)
+//! Email: michael@cyberdynea.io
+//!
+//! Permission is hereby granted, free of charge, to any person obtaining a copy of
+//! this software and associated documentation files (the "Software"), to deal in
+//! the Software without restriction, including without limitation the rights to
+//! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+//! the Software, and to permit persons to whom the Software is furnished to do so,
+//! subject to the following conditions:
+//!
+//! The above copyright notice and this permission notice shall be included in all
+//! copies or substantial portions of the Software.
+//!
+//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+//! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+//! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+//! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+//! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#[allow(unused_imports)]
+use anyhow::{Context, Error};
+use rand::distributions::{Alphanumeric, DistString};
+use rand::{thread_rng, Rng};
+use tokio::time::error::Elapsed;
+
+pub fn phrases(count: i32) -> Result<Vec<String>, Error> {
+    let rng_word_length = 10;
+    let rng_word_length_min = 3;
+
+    (0..count)
+        .map(|_| thread_rng().gen_range(rng_word_length_min..rng_word_length) as usize)
+        .map(|length| Alphanumeric.sample_string(&mut thread_rng(), length))
+        // NOTE: Optionally, while this example does not generate any empty words, if we wanted to filter through such a scenario, it can be done using a filter to generate an `Option`.
+        // .map(|word| Some(word).filter(|word| word.len() != 0))
+        // .map(|word| word.context(anyhow::anyhow!("Word length is 0!")))
+        .map(|word| Ok(word))
+        .collect()
+}
+
+pub fn phrases_randomized(count: usize, words_per_phrase: usize) -> Result<Vec<String>, Error> {
+    let rng_word_length = 10;
+    let rng_word_length_min = 3;
+
+    Ok((0..count)
+        .map(|_| {
+            (0..words_per_phrase)
+                .map(|_| thread_rng().gen_range(rng_word_length_min..rng_word_length) as usize)
+                .map(|length| Alphanumeric.sample_string(&mut thread_rng(), length))
+                .collect::<Vec<String>>()
+                .join(" ")
+        })
+        .collect())
+}