diff --git a/day5/ProgrammingInCXX_d5.pdf b/day5/ProgrammingInCXX_d5.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..5b981208945c982b482c5c85bfe0783ac28b9853
Binary files /dev/null and b/day5/ProgrammingInCXX_d5.pdf differ
diff --git a/day5/examples/TE/PolyVal.cc b/day5/examples/TE/PolyVal.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3d338f6c2c4d6da02d265ecc93a7fef2845022d3
--- /dev/null
+++ b/day5/examples/TE/PolyVal.cc
@@ -0,0 +1,68 @@
+#include <iostream>
+#include <memory>
+#include <vector>
+#include <type_traits>
+using namespace std::string_literals;
+
+void func1(int x) { std::cout << "Integer = " << x << "\n"; }
+void func1(double x) { std::cout << "Double = " << x << "\n"; }
+void func1(std::string x) { std::cout << "std::string = \"" << x << "\"\n"; }
+
+class PolyVal {
+    struct Internal {
+        virtual ~Internal() noexcept = default;
+        virtual auto clone() const -> std::unique_ptr<Internal> = 0;
+        virtual void func1_() const = 0;
+    };
+    template <class T>
+    struct Wrapped : public Internal {
+        Wrapped(T ex) : obj{ex} {}
+        ~Wrapped() noexcept override {}
+        auto clone() const -> std::unique_ptr<Internal> override
+        {
+            return std::make_unique<Wrapped>(obj);
+        }
+        void func1_() const override
+        {
+            func1(obj);
+        }
+        T obj;
+    };
+
+public:
+    template <class T>
+    PolyVal(const T& var) : ptr{ std::make_unique<Wrapped<T>>(var) } {}
+    PolyVal(const PolyVal& other) : ptr { other.ptr->clone() } {}
+
+private:
+    friend void func1(const PolyVal& pv) { pv.ptr->func1_(); }
+    std::unique_ptr<Internal> ptr;
+};
+
+auto f(int i) -> PolyVal
+{
+    if (i % 2 == 0)
+        return { 9 };
+    else
+        return { "Nine"s };
+}
+
+auto main() -> int
+{
+    std::vector<PolyVal> v;
+    v.push_back(1);
+    v.push_back(2.0);
+    v.push_back("Green"s);
+
+    for (auto&& elem : v) {
+        func1(elem);
+    }
+    std::cout << "------------\n";
+    for (int i = 0; i < 6; ++i) {
+        std::cout << "Calling function with i = " 
+            << i << " and receiving PolyVal by value\n";
+        PolyVal X = f(i);
+        func1(X);
+    }
+}
+
diff --git a/day5/examples/addables.cc b/day5/examples/addables.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0227058f45b08e0dacf0560f2b70af99cd14c207
--- /dev/null
+++ b/day5/examples/addables.cc
@@ -0,0 +1,23 @@
+#include <iostream>
+#include <string>
+#include <concepts>
+
+template <class T>
+concept Addable = requires(T a, T b) {
+    { a + b } -> std::convertible_to<T>;
+};
+
+auto aggregate(Addable auto... args)
+{
+    return (args + ...);
+}
+
+auto main() -> int
+{
+    using namespace std::string_literals;
+    std::cout << "aggregate(1, 2, 3, 4, 5) = "
+              << aggregate(1, 2, 3, 4, 5) << "\n";
+    std::cout << R"aw(aggregate("|-"s, "-|"s) = )aw"
+                << aggregate("|-"s, "-|"s) << "\n";
+}
+
diff --git a/day5/examples/dist.cc b/day5/examples/dist.cc
new file mode 100644
index 0000000000000000000000000000000000000000..adff40b2901d6091961dfea6ee478742dc427c8c
--- /dev/null
+++ b/day5/examples/dist.cc
@@ -0,0 +1,87 @@
+#include <array>
+#include <iostream>
+#include <iomanip>
+#include <cxx20format>
+#include <ctre.hpp>
+
+class Distance {
+public:
+    enum class unit : unsigned { metre = 0U,
+        kilometre = 1U,
+        centimetre = 2U };
+
+private:
+    static constexpr auto index(unit u) -> unsigned
+    {
+        return static_cast<unsigned>(u);
+    }
+    // The conv array has the factors you need to divide
+    // by to convert a value in a given unit to the
+    // internal representation, which is always in metres
+    static constexpr std::array conv { 1.0, 1.0e-3, 100.0 };
+    double val {}; // internal, always in metres
+public:
+    Distance() = default;
+    Distance(const Distance&) = default;
+    Distance(Distance&&) noexcept = default;
+    auto operator=(const Distance&) -> Distance& = default;
+    auto operator=(Distance&&) noexcept -> Distance& = default;
+    Distance(double v, unit u)
+        : val { v / conv[index(u)] }
+    {
+    }
+    auto value(unit in_unit) const noexcept { return val * conv[index(in_unit)]; }
+    void value(double v, unit u) { val = v / conv[index(u)]; }
+    void str(std::string_view sv);
+};
+
+auto operator""_m(long double inp) -> Distance { return { static_cast<double>(inp), Distance::unit::metre }; }
+auto operator""_km(long double inp) -> Distance { return { static_cast<double>(inp), Distance::unit::kilometre }; }
+auto operator""_cm(long double inp) -> Distance { return { static_cast<double>(inp), Distance::unit::centimetre }; }
+
+auto operator<<(std::ostream& os, const Distance& d) -> std::ostream&
+{
+    os << d.value(Distance::unit::metre) << "_m";
+    return os;
+}
+
+auto operator>>(std::istream& is, Distance& d) -> std::istream&
+{
+    std::string val;
+    is >> std::quoted(val);
+    d.str(val);
+    return is;
+}
+
+auto main() -> int
+{
+    Distance d { 4.0, Distance::unit::kilometre };
+    std::cout << d << "\n";
+    Distance c { 35.4_cm };
+    std::cout << c << "\n";
+    std::cout << "Enter distance: ";
+    std::cin >> d;
+    std::cout << "That's " << d << "\n";
+}
+
+void Distance::str(std::string_view diststr)
+{
+    static constexpr ctll::fixed_string trx {
+        R"(^(-?[0-9]*\.?[0-9]+)(_|[ ]*)(m|metre|metres|cm|centimetre|centimetres|km|kilometre|kilometres)$)"
+    };
+    if (auto m = ctre::match<trx>(diststr); m) {
+        auto numstr = m.get<1>().to_string();
+        auto num = std::stod(numstr);
+        auto ustr = m.get<3>().to_view();
+        if (ustr == "m" or ustr == "metre" or ustr == "metres") {
+            value(num, unit::metre);
+        } else if (ustr == "cm" or ustr == "centimetre" or ustr == "centimetres") {
+            value(num, unit::centimetre);
+        } else if (ustr == "km" or ustr == "kilometre" or ustr == "kilometres") {
+            value(num, unit::kilometre);
+        }
+    } else {
+        throw std::runtime_error(fmt::format(R"(Bad value "{}" for distance!)", diststr));
+    }
+}
+
diff --git a/day5/examples/format1.cc b/day5/examples/format1.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f4ec359ed86dd8393b95fbe0045f200f135d569d
--- /dev/null
+++ b/day5/examples/format1.cc
@@ -0,0 +1,17 @@
+#include <cxx20format>
+#include <iostream>
+#include <string>
+#include <tuple>
+
+auto main() -> int
+{
+    using namespace std;
+    using namespace std::string_literals;
+
+    for (auto i = 0UL; i < 110UL; ++i) {
+        std::cout << fmt::format(
+           "i = {0:010d}, E_tot = {2:16.12f}, E_hb = {1:8.4f}\n", 
+           i, exp(cos(1.0 * i)), exp(sin(1.0 * i))
+        );
+    }
+}
diff --git a/day5/examples/modules/2_any/with_header_files/CMakeLists.txt b/day5/examples/modules/2_any/with_header_files/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dc560625780ee2054e381df8ae532956e6a3de0b
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(polymorphic_w_any CXX)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set(Headers Point.hh Polygon.hh Triangle.hh Circle.hh)
+add_executable(${PROJECT_NAME} Point.cc Triangle.cc Circle.cc main.cc ${Headers})
+
diff --git a/day5/examples/modules/2_any/with_header_files/Circle.cc b/day5/examples/modules/2_any/with_header_files/Circle.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6ae0fa5582a3385e0d4f1c1480d956797f994e46
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Circle.cc
@@ -0,0 +1,26 @@
+#include "Circle.hh"
+
+constexpr double pi = 3.141592653589793;
+
+Circle::Circle(double rad, const Point& p)
+    : r{ rad }
+    , c{ p }
+{
+}
+
+double Circle::area() const
+{
+    return pi * r * r;
+}
+
+double Circle::perimeter() const
+{
+    return 2 * pi * r;
+}
+
+void Circle::rotate(double phi) { phi = 0; }
+
+void Circle::translate(Point p)
+{
+    c += p;
+}
diff --git a/day5/examples/modules/2_any/with_header_files/Circle.hh b/day5/examples/modules/2_any/with_header_files/Circle.hh
new file mode 100644
index 0000000000000000000000000000000000000000..adee3d74ca3c027cd74ddd180782fb4aed86fef9
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Circle.hh
@@ -0,0 +1,26 @@
+#ifndef Circle_HH
+#define Circle_HH
+#include "Point.hh"
+#include <string>
+
+class Circle {
+public:
+    Circle() = default;
+    Circle(double rad, const Point& p);
+    Circle(const Circle& cir) = default;
+    Circle(Circle&& cir) = default;
+    Circle& operator=(const Circle& cir) = default;
+    Circle& operator=(Circle&& cir) = default;
+    std::string name() const { return "Circle"; }
+    void rotate(double phi);
+    void translate(Point p);
+    double area() const;
+    double perimeter() const;
+    inline double circumference() const { return perimeter(); }
+
+private:
+    double r{ 1.0 };
+    Point c{}; // Use default constructor of class Point to create c
+};
+
+#endif
diff --git a/day5/examples/modules/2_any/with_header_files/Point.cc b/day5/examples/modules/2_any/with_header_files/Point.cc
new file mode 100644
index 0000000000000000000000000000000000000000..74ddec6e7e995d547fd04da729d083a8c6ad1bfc
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Point.cc
@@ -0,0 +1,53 @@
+#include "Point.hh"
+#include <iostream>
+
+Point::Point(double x, double y)
+    : X{ x }
+    , Y{ y }
+{
+}
+
+Point& Point::operator+=(const Point& p)
+{
+    X += p.X;
+    Y += p.Y;
+    return *this;
+}
+
+Point& Point::operator-=(const Point& p)
+{
+    X -= p.X;
+    Y -= p.Y;
+    return *this;
+}
+
+Point Point::operator+(const Point& p) const
+{
+    return { X + p.X, Y + p.Y };
+}
+
+Point Point::operator-(const Point& p) const
+{
+    return { X - p.X, Y - p.Y };
+}
+
+double Point::operator*(const Point& p) const
+{
+    return (X * p.X + Y * p.Y);
+}
+
+Point Point::operator*(double f) const
+{
+    return { f * X, f * Y };
+}
+
+Point operator*(double f, const Point& p)
+{
+    return { f * p.X, f * p.Y };
+}
+
+std::ostream& operator<<(std::ostream& os, const Point& p)
+{
+    os << "(" << p.X << ", " << p.Y << ")";
+    return os;
+}
diff --git a/day5/examples/modules/2_any/with_header_files/Point.hh b/day5/examples/modules/2_any/with_header_files/Point.hh
new file mode 100644
index 0000000000000000000000000000000000000000..009c99a6dcfddc155364e2465cc31da8ec785e0f
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Point.hh
@@ -0,0 +1,23 @@
+#ifndef Point_HH
+#define Point_HH
+class ostream;
+struct Point {
+    double X = 0, Y = 0;
+    Point() = default;
+    Point(const Point&) = default;
+    Point(Point&&) = default;
+    Point& operator=(const Point& p) = default;
+    Point& operator=(Point&& p) = default;
+    Point(double x, double y);
+    Point& operator+=(const Point& p);
+    Point& operator-=(const Point& p);
+    Point operator+(const Point& p) const;
+    Point operator-(const Point& p) const;
+    double operator*(const Point& p) const;
+    Point operator*(double f) const;
+};
+
+Point operator*(double f, const Point& p);
+ostream& operator<<(ostream& os, const Point& p);
+
+#endif
diff --git a/day5/examples/modules/2_any/with_header_files/Polygon.hh b/day5/examples/modules/2_any/with_header_files/Polygon.hh
new file mode 100644
index 0000000000000000000000000000000000000000..8c71504ae0e64fe47441651b1a339997f1c2676c
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Polygon.hh
@@ -0,0 +1,53 @@
+#ifndef Polygon_HH
+#define Polygon_HH
+#include "Point.hh"
+#include <array>
+#include <cmath>
+#include <string>
+
+template <unsigned int NV>
+class Polygon {
+    static_assert(NV > 2, "Can't have polygon with less than 3 sides");
+
+public:
+    Polygon() = default;
+    Polygon(const Polygon&) = default;
+    Polygon(Polygon&&) = default;
+    Polygon& operator=(const Polygon& pg) = default;
+    Polygon& operator=(Polygon&&) = default;
+    constexpr auto n_vertexes() const { return NV; }
+    std::string name() const { return "Polygon<" + std::to_string(NV) + ">"; }
+
+    double perimeter() const
+    {
+        double ans = 0;
+        for (size_t i = 1; i < vertex.size(); ++i) {
+            ans += sqrt((vertex[i] - vertex[i - 1]) * (vertex[i] - vertex[i - 1]));
+        }
+        ans += sqrt((vertex.front() - vertex.back()) * (vertex.front() - vertex.back()));
+        return ans;
+    }
+    void translate(Point p)
+    {
+        for (auto& pt : vertex)
+            pt += p;
+    }
+
+    void rotate(double phi)
+    {
+        Point center;
+        for (auto pt : vertex)
+            center += pt;
+        center = (1.0 / NV) * center;
+        double ct = cos(phi), st = sin(phi);
+        for (auto& pt : vertex) {
+            auto rel = pt - center;
+            pt = center + Point(ct * rel.X + st * rel.Y, -st * rel.X + ct * rel.Y);
+        }
+    }
+
+protected:
+    std::array<Point, NV> vertex;
+};
+
+#endif
diff --git a/day5/examples/modules/2_any/with_header_files/Triangle.cc b/day5/examples/modules/2_any/with_header_files/Triangle.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b27b4ae583252f7ad306f65146f668e1f49adbba
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Triangle.cc
@@ -0,0 +1,22 @@
+#include "Triangle.hh"
+#include <cmath>
+// A "static" function in a source file (not a static member function of a class)
+// is meant to be visible only in the same translation unit, most often just that
+// source file.
+static inline double sqr(Point p) { return p * p; }
+
+Triangle::Triangle(Point p1, Point p2, Point p3)
+{
+    vertex[0] = p1;
+    vertex[1] = p2;
+    vertex[2] = p3;
+}
+
+double Triangle::area() const
+{
+    double s = 0.5 * perimeter();
+    double a = sqrt(sqr(vertex[0] - vertex[1]));
+    double b = sqrt(sqr(vertex[0] - vertex[2]));
+    double c = sqrt(sqr(vertex[1] - vertex[2]));
+    return sqrt(s * (s - a) * (s - b) * (s - c));
+}
diff --git a/day5/examples/modules/2_any/with_header_files/Triangle.hh b/day5/examples/modules/2_any/with_header_files/Triangle.hh
new file mode 100644
index 0000000000000000000000000000000000000000..c360fc50f97a275711454e8fe1eda0c0680b9fbe
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/Triangle.hh
@@ -0,0 +1,9 @@
+#include "Polygon.hh"
+
+class Triangle : public Polygon<3> {
+public:
+    using Polygon<3>::Polygon;
+    using Polygon<3>::operator=;
+    Triangle(Point p1, Point p2, Point p3);
+    double area() const;
+};
diff --git a/day5/examples/modules/2_any/with_header_files/main.cc b/day5/examples/modules/2_any/with_header_files/main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7bbab1e58c41f6d88dbd02fef9b19bb6e0a86efc
--- /dev/null
+++ b/day5/examples/modules/2_any/with_header_files/main.cc
@@ -0,0 +1,91 @@
+#include "Circle.hh"
+#include "Triangle.hh"
+#include <chrono>
+#include <random>
+#include <iostream>
+#include <vector>
+#include <any>
+
+constexpr auto N = 100000ul;
+std::mt19937_64 engine;
+std::discrete_distribution sel{ 0.5, 0.5 };
+std::exponential_distribution length{ 1.0 };
+
+using element_type = std::any;
+
+auto name(const std::vector<element_type>& v, size_t i)
+{
+    if (v[i].type() == typeid(Triangle)) {
+        return std::any_cast<Triangle>(v[i]).name();
+    } else {
+        return std::any_cast<Circle>(v[i]).name();
+    }
+}
+
+auto area(const std::vector<element_type>& v, size_t i)
+{
+    if (v[i].type() == typeid(Triangle)) {
+        return std::any_cast<Triangle>(v[i]).area();
+    } else {
+        return std::any_cast<Circle>(v[i]).area();
+    }
+}
+
+void construct_objects(std::vector<element_type>& v)
+{
+    for (auto i = 0ul; i < N; ++i) {
+        auto isel = sel(engine);
+        switch (isel) {
+        case 0: {
+            auto radius = length(engine);
+            auto centrepos = Point(length(engine), length(engine));
+            v.emplace_back(std::in_place_type_t<Circle>{}, radius, centrepos);
+            break;
+        }
+        case 1: {
+            auto v1 = Point(length(engine), length(engine));
+            auto v2 = Point(length(engine), length(engine));
+            auto v3 = Point(length(engine), length(engine));
+            v.emplace_back(std::in_place_type_t<Triangle>{}, v1, v2, v3);
+            break;
+        }
+        };
+    }
+}
+
+void calc_area_all(const std::vector<element_type>& v)
+{
+    auto max_loc = 0ul;
+    auto max_area = 0.;
+    for (size_t i = 0; i < v.size(); ++i) {
+        auto ar = area(v, i);
+        if (i < 5) {
+            std::cout << i << ": " << name(v, i) << " with area "
+                      << ar << "\n";
+        }
+        if (ar > max_area) {
+            max_loc = i;
+        }
+    }
+
+    std::cout << "Largest object: \n";
+    auto nm = name(v, max_loc);
+    auto ar = area(v, max_loc);
+    std::cout << "Name : " << nm << ", area = " << ar << "\n";
+}
+
+int main()
+{
+    std::vector<element_type> shapes;
+    shapes.reserve(N);
+
+    auto t0 = std::chrono::steady_clock::now();
+    construct_objects(shapes);
+    auto t1 = std::chrono::steady_clock::now();
+    calc_area_all(shapes);
+    auto t2 = std::chrono::steady_clock::now();
+    std::cout << "Object creation time for " << N << " objects, "
+              << std::chrono::duration<double>(t1 - t0).count() << "\n"
+              << "Area evaluation time for " << N << " objects, "
+              << std::chrono::duration<double>(t2 - t1).count() << "\n";
+}
diff --git a/day5/examples/modules/2_any/with_modules/CMakeLists.txt b/day5/examples/modules/2_any/with_modules/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c9911f04457fcecd015f92b28f58bafe1f1d7ab5
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/CMakeLists.txt
@@ -0,0 +1,82 @@
+cmake_minimum_required(VERSION 3.18)
+
+project(polymorphic_w_any CXX)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set (CMAKE_CXX_STANDARD 20)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+
+include(CheckCXXCompilerFlag)
+check_cxx_compiler_flag(-fmodules HAS_FMODULES)
+if (HAS_FMODULES)
+    set(COMPILE_FLAGS -fmodules ${COMPILE_FLAGS})
+else()
+    check_cxx_compiler_flag(-fmodules-ts HAS_FMODULES_TS)
+    if (HAS_FMODULES_TS)
+        set(COMPILE_FLAGS -fmodules-ts ${COMPILE_FLAGS})
+    else()
+        message(FATAL_ERROR "This compiler does not have either of the options -fmodules or -fmodules-ts!")
+    endif()
+endif()
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+if (NOT CMI_CACHE)
+        set(CMI_CACHE ${PROJECT_BINARY_DIR}/pcm.cache)
+endif()
+	set(CMI_EXT ".pcm")
+        set(COMPILE_FLAGS ${COMPILE_FLAGS} -std=c++20 -stdlib=libc++ -fbuiltin-module-map -fprebuilt-module-path=${CMI_CACHE})
+        set(MIFC_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} --precompile -xc++-module)
+        set(MIMP_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} -xc++ -c)
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+if (NOT CMI_CACHE)
+        set(CMI_CACHE ${PROJECT_BINARY_DIR}/gcm.cache)
+endif()
+	set(CMI_EXT ".gcm")
+    message(STATUS "Generating standard library header units.")
+        execute_process(COMMAND ${PROJECT_SOURCE_DIR}/make_gcm_cache.sh
+                WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
+                OUTPUT_VARIABLE CMI_CACHE
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+    message(STATUS "Done.")
+    set(MIFC_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} -std=c++20 -c -xc++)
+    set(MIMP_BUILD_FLAGS ${COMPILE_FLAGS} ${CMAKE_CXX_FLAGS})
+else()
+    message(FATAL_ERROR "Unsupported compiler ...")
+endif()
+file(MAKE_DIRECTORY ${CMI_CACHE})
+set(ADDITIONAL_CLEAN_FILES ${CMI_CACHE})
+
+function(module_interface out_var)
+  set(result)
+  foreach(in_f ${ARGN})
+    file(RELATIVE_PATH out_f ${CMAKE_CURRENT_SOURCE_DIR} ${in_f})
+    string(REGEX REPLACE "[.]ixx$" ${CMI_EXT} out_f ${out_f})
+    set(out_f "${CMI_CACHE}/${out_f}")
+    add_custom_command(OUTPUT ${out_f}
+            COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -o ${out_f} ${MIFC_BUILD_FLAGS} ${in_f}
+      DEPENDS ${in_f}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+      COMMENT "Creating module interface file ${out_f}"
+      VERBATIM
+      )
+    list(APPEND result ${out_f})
+  endforeach()
+  set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+module_interface(mod_Point ${CMAKE_CURRENT_SOURCE_DIR}/Point.ixx)
+module_interface(mod_Circle ${CMAKE_CURRENT_SOURCE_DIR}/Circle.ixx)
+module_interface(mod_Polygon ${CMAKE_CURRENT_SOURCE_DIR}/Polygon.ixx)
+module_interface(mod_Triangle ${CMAKE_CURRENT_SOURCE_DIR}/Triangle.ixx)
+
+set(mods ${mod_Point} ${mod_Circle} ${mod_Polygon} ${mod_Triangle})
+add_library(shapes
+        ${mods} 
+	Point.ixx
+	Circle.ixx
+	Polygon.ixx
+	Triangle.ixx
+)
+target_compile_options(shapes PRIVATE ${MIMP_BUILD_FLAGS})
+add_executable(${PROJECT_NAME} main.cc)
+target_link_libraries(${PROJECT_NAME} shapes)
+target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_FLAGS})
+
diff --git a/day5/examples/modules/2_any/with_modules/Circle.ixx b/day5/examples/modules/2_any/with_modules/Circle.ixx
new file mode 100644
index 0000000000000000000000000000000000000000..31fbfc6f7952cd9565c229b50182841bebe8c44d
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/Circle.ixx
@@ -0,0 +1,51 @@
+module;
+import <string>;
+import <numbers>;
+import Point;
+export module Circle;
+
+using std::numbers::pi;
+
+export class Circle {
+public:
+    Circle() = default;
+    Circle(double rad, const Point& p);
+    Circle(const Circle& cir) = default;
+    Circle(Circle&& cir) = default;
+    Circle& operator=(const Circle& cir) = default;
+    Circle& operator=(Circle&& cir) = default;
+    std::string name() const { return "Circle"; }
+    void rotate(double phi);
+    void translate(Point p);
+    double area() const;
+    double perimeter() const;
+    inline double circumference() const { return perimeter(); }
+
+private:
+    double r{ 1.0 };
+    Point c{}; // Use default constructor of class Point to create c
+};
+
+
+Circle::Circle(double rad, const Point& p)
+    : r{ rad }
+    , c{ p }
+{
+}
+
+double Circle::area() const
+{
+    return pi * r * r;
+}
+
+double Circle::perimeter() const
+{
+    return 2 * pi * r;
+}
+
+void Circle::rotate(double phi) { phi = 0; }
+
+void Circle::translate(Point p)
+{
+    c += p;
+}
diff --git a/day5/examples/modules/2_any/with_modules/Point.ixx b/day5/examples/modules/2_any/with_modules/Point.ixx
new file mode 100644
index 0000000000000000000000000000000000000000..8677861201e38b971b41336da0f246652c8d004e
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/Point.ixx
@@ -0,0 +1,73 @@
+module;
+import <iostream>;
+export module Point;
+
+export struct Point {
+    double X = 0, Y = 0;
+    Point() = default;
+    Point(const Point&) = default;
+    Point(Point&&) = default;
+    Point& operator=(const Point& p) = default;
+    Point& operator=(Point&& p) = default;
+    Point(double x, double y);
+    Point& operator+=(const Point& p);
+    Point& operator-=(const Point& p);
+    Point operator+(const Point& p) const;
+    Point operator-(const Point& p) const;
+    double operator*(const Point& p) const;
+    Point operator*(double f) const;
+};
+
+export auto operator*(double f, const Point& p) -> Point;
+export auto operator<<(std::ostream& os, const Point& p) -> std::ostream&;
+
+Point::Point(double x, double y)
+    : X{ x }
+    , Y{ y }
+{
+}
+
+Point& Point::operator+=(const Point& p)
+{
+    X += p.X;
+    Y += p.Y;
+    return *this;
+}
+
+Point& Point::operator-=(const Point& p)
+{
+    X -= p.X;
+    Y -= p.Y;
+    return *this;
+}
+
+Point Point::operator+(const Point& p) const
+{
+    return { X + p.X, Y + p.Y };
+}
+
+Point Point::operator-(const Point& p) const
+{
+    return { X - p.X, Y - p.Y };
+}
+
+double Point::operator*(const Point& p) const
+{
+    return (X * p.X + Y * p.Y);
+}
+
+Point Point::operator*(double f) const
+{
+    return { f * X, f * Y };
+}
+
+Point operator*(double f, const Point& p)
+{
+    return { f * p.X, f * p.Y };
+}
+
+std::ostream& operator<<(std::ostream& os, const Point& p)
+{
+    os << "(" << p.X << ", " << p.Y << ")";
+    return os;
+}
diff --git a/day5/examples/modules/2_any/with_modules/Polygon.ixx b/day5/examples/modules/2_any/with_modules/Polygon.ixx
new file mode 100644
index 0000000000000000000000000000000000000000..8f10afdb2bcd5dc434da5653c9bee632e1a05926
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/Polygon.ixx
@@ -0,0 +1,52 @@
+module;
+import <cmath>;
+import <array>;
+import <string>;
+export module Polygon;
+import Point;
+
+export template <unsigned int NV>
+class Polygon {
+    static_assert(NV > 2, "Can't have polygon with less than 3 sides");
+
+public:
+    Polygon() = default;
+    Polygon(const Polygon&) = default;
+    Polygon(Polygon&&) = default;
+    Polygon& operator=(const Polygon& pg) = default;
+    Polygon& operator=(Polygon&&) = default;
+    constexpr auto n_vertexes() const { return NV; }
+    inline std::string name() const { return "Polygon<" + std::to_string(NV) + ">"; }
+
+    double perimeter() const
+    {
+        double ans = 0;
+        for (size_t i = 1; i < vertex.size(); ++i) {
+            ans += sqrt((vertex[i] - vertex[i - 1]) * (vertex[i] - vertex[i - 1]));
+        }
+        ans += sqrt((vertex.front() - vertex.back()) * (vertex.front() - vertex.back()));
+        return ans;
+    }
+    void translate(Point p)
+    {
+        for (auto& pt : vertex)
+            pt += p;
+    }
+
+    void rotate(double phi)
+    {
+        Point center;
+        for (auto pt : vertex)
+            center += pt;
+        center = (1.0 / NV) * center;
+        double ct = cos(phi), st = sin(phi);
+        for (auto& pt : vertex) {
+            auto rel = pt - center;
+            pt = center + Point(ct * rel.X + st * rel.Y, -st * rel.X + ct * rel.Y);
+        }
+    }
+
+protected:
+    std::array<Point, NV> vertex;
+};
+
diff --git a/day5/examples/modules/2_any/with_modules/Triangle.ixx b/day5/examples/modules/2_any/with_modules/Triangle.ixx
new file mode 100644
index 0000000000000000000000000000000000000000..50647c4aa95389c91d941367db186e9c077976ab
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/Triangle.ixx
@@ -0,0 +1,33 @@
+module;
+import <array>;
+import <cmath>;
+export module Triangle;
+import Polygon;
+import Point;
+
+export class Triangle : public Polygon<3U> {
+public:
+    using Polygon<3U>::Polygon;
+    using Polygon<3U>::operator=;
+    using Polygon<3U>::name;
+    Triangle(Point p1, Point p2, Point p3);
+    double area() const;
+};
+// not exported
+inline double sqr(Point p) { return p * p; }
+
+Triangle::Triangle(Point p1, Point p2, Point p3)
+{
+    vertex[0] = p1;
+    vertex[1] = p2;
+    vertex[2] = p3;
+}
+
+double Triangle::area() const
+{
+    double s = 0.5 * perimeter();
+    double a = sqrt(sqr(vertex[0] - vertex[1]));
+    double b = sqrt(sqr(vertex[0] - vertex[2]));
+    double c = sqrt(sqr(vertex[1] - vertex[2]));
+    return sqrt(s * (s - a) * (s - b) * (s - c));
+}
diff --git a/day5/examples/modules/2_any/with_modules/build_with_clang.sh b/day5/examples/modules/2_any/with_modules/build_with_clang.sh
new file mode 100755
index 0000000000000000000000000000000000000000..81d5b5f6b359645040506e66e7807c0d1537c159
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/build_with_clang.sh
@@ -0,0 +1,13 @@
+for m in Point Circle Polygon Triangle; do
+echo "Generating CMI for $m"
+clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. --precompile -xc++-module $m.ixx
+done
+for m in Point Circle Polygon Triangle; do
+echo "Generating object file for $m"
+clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. -xc++ -c $m.ixx
+done
+echo "Compiling main.cc -> a.clg"
+clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. -o a.clg main.cc Point.o Circle.o Polygon.o Triangle.o
+
+
+
diff --git a/day5/examples/modules/2_any/with_modules/build_with_gcc.sh b/day5/examples/modules/2_any/with_modules/build_with_gcc.sh
new file mode 100755
index 0000000000000000000000000000000000000000..556aad4b8dbd4a3161e8cd27b10be5f6dfafe0f9
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/build_with_gcc.sh
@@ -0,0 +1,17 @@
+for h in string cmath iostream charconv numbers array chrono random vector any; do
+echo "Generating library header unit for $h"
+g++ -std=c++20 -fmodules-ts -xc++-system-header $h
+done
+
+for m in Point Circle Polygon Triangle; do
+echo "Generating CMI and object files for $m"
+g++ -std=c++20 -fmodules-ts -xc++ -c $m.ixx
+done
+echo "Compiling main.cc -> a.gcc"
+g++ -std=c++20 -fmodules-ts -static -o a.gcc main.cc Point.o Circle.o Polygon.o Triangle.o
+
+echo "GCC module implementation is not in a usable state as of May 2022."
+echo "Check if the example builds and runs."
+
+
+
diff --git a/day5/examples/modules/2_any/with_modules/clean.sh b/day5/examples/modules/2_any/with_modules/clean.sh
new file mode 100755
index 0000000000000000000000000000000000000000..aff1f9ecfd5fea4825d71d4e1af2f0c4ccfe57f6
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/clean.sh
@@ -0,0 +1,4 @@
+rm -f *.o *.pcm *.gcm
+rm -rf gcm.cache
+rm -f a.clg a.gcc
+
diff --git a/day5/examples/modules/2_any/with_modules/main.cc b/day5/examples/modules/2_any/with_modules/main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e66f6893cc68716d42f35cbbd265a251231a7150
--- /dev/null
+++ b/day5/examples/modules/2_any/with_modules/main.cc
@@ -0,0 +1,95 @@
+import Point;
+import Polygon;
+import Circle;
+import Triangle;
+import <chrono>;
+import <random>;
+import <iostream>;
+import <vector>;
+import <array>;
+import <any>;
+
+constexpr auto N = 100000UL;
+std::mt19937_64 engine;
+std::discrete_distribution sel{ 0.5, 0.5 };
+std::exponential_distribution length{ 1.0 };
+
+using element_type = std::any;
+
+auto name(const std::vector<element_type>& v, size_t i)
+{
+    if (v[i].type() == typeid(Triangle)) {
+        return std::any_cast<Triangle>(v[i]).name();
+    } else {
+        return std::any_cast<Circle>(v[i]).name();
+    }
+}
+
+auto area(const std::vector<element_type>& v, size_t i)
+{
+    if (v[i].type() == typeid(Triangle)) {
+        return std::any_cast<Triangle>(v[i]).area();
+    } else {
+        return std::any_cast<Circle>(v[i]).area();
+    }
+}
+
+void construct_objects(std::vector<element_type>& v)
+{
+    for (auto i = 0ul; i < N; ++i) {
+        auto isel = sel(engine);
+        switch (isel) {
+        case 0: {
+            auto radius = length(engine);
+            auto centrepos = Point(length(engine), length(engine));
+            v.emplace_back(std::in_place_type_t<Circle>{}, radius, centrepos);
+            break;
+        }
+        case 1: {
+            auto v1 = Point(length(engine), length(engine));
+            auto v2 = Point(length(engine), length(engine));
+            auto v3 = Point(length(engine), length(engine));
+            v.emplace_back(std::in_place_type_t<Triangle>{}, v1, v2, v3);
+            break;
+        }
+        };
+    }
+}
+
+void calc_area_all(const std::vector<element_type>& v)
+{
+    auto max_loc = 0ul;
+    auto max_area = 0.;
+    for (size_t i = 0; i < v.size(); ++i) {
+        auto ar = area(v, i);
+        if (i < 5) {
+            std::cout << i << ": " << name(v, i) << " with area "
+                      << ar << "\n";
+        }
+        if (ar > max_area) {
+            max_loc = i;
+        }
+    }
+
+    std::cout << "Largest object: \n";
+    auto nm = name(v, max_loc);
+    auto ar = area(v, max_loc);
+    std::cout << "Name : " << nm << ", area = " << ar << "\n";
+}
+
+auto main() -> int
+{
+    std::vector<element_type> shapes;
+    shapes.reserve(N);
+
+    auto t0 = std::chrono::steady_clock::now();
+    construct_objects(shapes);
+    auto t1 = std::chrono::steady_clock::now();
+    calc_area_all(shapes);
+    auto t2 = std::chrono::steady_clock::now();
+    std::cout << "Object creation time for " << N << " objects, "
+              << std::chrono::duration<double>(t1 - t0).count() << "\n"
+              << "Area evaluation time for " << N << " objects, "
+              << std::chrono::duration<double>(t2 - t1).count() << "\n";
+}
+
diff --git a/day5/examples/modules/darray_module/README.md b/day5/examples/modules/darray_module/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9ec4314058e015bc8ecb0e2a9238786e4f6144d6
--- /dev/null
+++ b/day5/examples/modules/darray_module/README.md
@@ -0,0 +1,4 @@
+clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps --precompile -xc++-module -fprebuilt-module-path=. mymodule.ixx
+clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-module-maps -fprebuilt-module-path=. main.cc
+
+
diff --git a/day5/examples/modules/darray_module/main.cc b/day5/examples/modules/darray_module/main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..29ffc819c827dcff1825e6d37d3445d3e8ddde6d
--- /dev/null
+++ b/day5/examples/modules/darray_module/main.cc
@@ -0,0 +1,21 @@
+#include <string>
+#include <iostream>
+import mymodule;
+
+auto main() -> int
+{
+    darray d1 { 1, 2, 3, 4, 5 }; // CTAD works!
+    //darray<int> d1{1, 2, 3, 4, 5};
+    darray<std::string> d2 { "a", "b", "c" }; 
+    // Explicit type required above, since "a", "b" etc are C-strings, and we want C++ strings
+    auto d3 = d1; //Copy
+    darray<int> d4 { 10 }; // This and the following line have a subtle difference
+    darray<int> d5(10); // This is the only situation where constructor calls with {} and () mean different things.
+    darray<std::string> d6 { std::move(d2) }; // d2 should be empty and d6 must have all data after this.
+    std::cout << "d1 = " << d1 << "\n";
+    std::cout << "d2 = " << d2 << "\n";
+    std::cout << "d3 = " << d3 << "\n";
+    std::cout << "d4 = " << d4 << "\n";
+    std::cout << "d5 = " << d5 << "\n";
+    std::cout << "d6 = " << d6 << "\n";
+}
diff --git a/day5/examples/modules/darray_module/mymodule.ixx b/day5/examples/modules/darray_module/mymodule.ixx
new file mode 100644
index 0000000000000000000000000000000000000000..8c9f3bbab6290aadf88158fbb5395393c1c2c8a5
--- /dev/null
+++ b/day5/examples/modules/darray_module/mymodule.ixx
@@ -0,0 +1,103 @@
+module;
+#include <initializer_list>
+#include <iostream>
+#include <memory>
+export module mymodule;
+
+export template <class T>
+class darray {
+private:
+    // swap function
+    void swap(darray& oth)
+    {
+        std::swap(arr, oth.arr);
+        std::swap(sz, oth.sz);
+    }
+    std::unique_ptr<T[]> arr;
+    size_t sz = 0;
+
+public:
+    // read-only access for array elements
+    auto operator[](size_t i) const -> T { return arr[i]; }
+    // read-write access for array elements
+    auto operator[](size_t i) -> T& { return arr[i]; }
+
+    // This is needed if you want to use range based for loops on your class
+    auto begin() const -> T* { return arr; }
+    // This is needed if you want to use range based for loops on your class
+    auto end() const -> T* { return arr + size(); }
+
+    // returns the size
+    auto size() const -> decltype(sz) { return sz; }
+
+    // Sums up array and returns the result
+    auto sum() const -> T
+    {
+        T a {};
+        for (auto el : (*this)) {
+            a += el;
+        } // Use the range based for loop. //Well, why not!
+        return a;
+    }
+
+    // Default constructor, also defaulted.
+    darray() = default;
+    // Destructor. With storage managed by a unique_ptr, we don't need to delete it.
+    ~darray() = default;
+
+    // Constructor with a given size
+    darray(size_t N)
+    {
+        if (N != 0) {
+            arr = std::make_unique<T[]>(N);
+            sz = N;
+        }
+    }
+
+    // Copy constructor
+    darray(const darray<T>& oth)
+    {
+        if (oth.sz != 0) {
+            sz = oth.sz;
+            arr = std::make_unique<T[]>(sz);
+        }
+        for (size_t i = 0; i < sz; ++i)
+            arr[i] = oth.arr[i];
+    }
+    darray(darray<T>&& oth) noexcept 
+    {
+         swap(oth);
+    }
+    // Initialiser list constructor
+    darray(std::initializer_list<T> l)
+    {
+        arr = std::make_unique<T[]>(l.size());
+        sz = l.size();
+        size_t i = 0;
+        for (auto el : l)
+            arr[i++] = el;
+    }
+    // Assignment operator using the copy and swap idiom
+    auto operator=(darray d) -> darray&
+    {
+        swap(d);
+        return *this;
+    }
+};
+
+// Output operator. No need to make it a friend, since we can use only
+// public functions of the class to do all the work!
+export template <typename T>
+auto operator<<(std::ostream& os, const darray<T>& d) -> std::ostream&
+{
+    os << '[';
+    for (size_t i = 0; i < d.size(); ++i) {
+        os << d[i];
+        if (i != (d.size() - 1))
+            os << ',';
+    }
+    os << ']';
+    return os; // This function returns os so that you can write cout << d1 << " other things\n";
+    // That is interpreted as (cout << d1) << " other things\n";
+}
+
diff --git a/day5/examples/modules/hello_m.cc b/day5/examples/modules/hello_m.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f743015337ce7b049038e5ba97b0fca1e08ae90d
--- /dev/null
+++ b/day5/examples/modules/hello_m.cc
@@ -0,0 +1,7 @@
+import <iostream>;
+
+auto main() -> int
+{
+    std::cout << "Hello, world!\n";
+}
+
diff --git a/day5/examples/modules/saxpy/with_header_files/README.md b/day5/examples/modules/saxpy/with_header_files/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..373387081bbac91d2934735b2044dfa48e2760b3
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_header_files/README.md
@@ -0,0 +1,9 @@
+To compile with clang:
+
+clang++ -std=c++20 -stdlib=libc++ usesaxpy.cc
+
+With gcc:
+
+g++ -std=c++20 usesaxpy.cc
+
+
diff --git a/day5/examples/modules/saxpy/with_header_files/saxpy.hh b/day5/examples/modules/saxpy/with_header_files/saxpy.hh
new file mode 100644
index 0000000000000000000000000000000000000000..b52279919867975fe7df82da673a55b6e071eae5
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_header_files/saxpy.hh
@@ -0,0 +1,21 @@
+#ifndef SAXPY_HH
+#define SAXPY_HH
+#include <algorithm>
+#include <span>
+
+template <class T>
+concept Number = std::floating_point<T>
+              or std::integral<T>;
+template <Number T>
+auto saxpy(T a, std::span<const T> x,
+           std::span<const T> y,
+           std::span<T> z)
+{
+    std::transform(x.begin(), x.end(),
+                   y.begin(), z.begin(),
+        [a](T X, T Y) {
+            return a * X + Y;
+        });
+}
+#endif
+
diff --git a/day5/examples/modules/saxpy/with_header_files/usesaxpy.cc b/day5/examples/modules/saxpy/with_header_files/usesaxpy.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2a5386031e9b5790e757398d286489e9282fb5ed
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_header_files/usesaxpy.cc
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <array>
+#include <vector>
+#include <span>
+#include "saxpy.hh"
+
+auto main() -> int
+{
+    using namespace std;
+    const array inp1 { 1., 2., 3., 4., 5. };
+    const array inp2 { 9., 8., 7., 6., 5. };
+    vector outp(inp1.size(), 0.);
+
+    saxpy(10., {inp1}, {inp2}, {outp});
+    for (auto x : outp) cout << x << "\n";
+    cout << ":::::::::::::::::::::\n";
+}
+
diff --git a/day5/examples/modules/saxpy/with_modules/README.md b/day5/examples/modules/saxpy/with_modules/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1ce1183e9dd555e2b4d05bfa46c19f58c5e563a8
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_modules/README.md
@@ -0,0 +1,12 @@
+Compile with clang:
+
+clang++ -std=c++20 -stdlib=libc++ -fmodules -xc++-module --precompile saxpy.ixx
+clang++ -std=c++20 -stdlib=libc++ -fmodules -fprebuilt-module-path=. usesaxpy.cc
+
+If you want to compile with GCC, change the imports back to
+old style includes, and then do this:
+
+g++ -std=c++20 -fmodules-ts -xc++ -c saxpy.ixx
+g++ -std=c++20 -fmodules-ts saxpy.o usesaxpy.cc
+
+
diff --git a/day5/examples/modules/saxpy/with_modules/cleanup.sh b/day5/examples/modules/saxpy/with_modules/cleanup.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4421c4cf16b8f2e806da5f525ec5dfd91a286001
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_modules/cleanup.sh
@@ -0,0 +1,3 @@
+rm -rf gcm.cache saxpy.pcm *.o a.out
+
+
diff --git a/day5/examples/modules/saxpy/with_modules/saxpy.ixx b/day5/examples/modules/saxpy/with_modules/saxpy.ixx
new file mode 100644
index 0000000000000000000000000000000000000000..47a8a348ed4b296b74159d5b4474d57467e32bc3
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_modules/saxpy.ixx
@@ -0,0 +1,29 @@
+/* We are using #includes rather than imports
+to be able to compile with gcc. Clang works
+fine with the imports of STL headers. GCC,
+even after generating header units with
+-xc++-system-header crashes with an internal
+compiler error.
+*/
+
+module;
+#include <algorithm>
+#include <span>
+export module saxpy;
+
+template <class T>
+concept Number = std::floating_point<T>
+              or std::integral<T>;
+
+export template <Number T>
+auto saxpy(T a, std::span<const T> x,
+           std::span<const T> y,
+           std::span<T> z)
+{
+    std::transform(x.begin(), x.end(),
+                   y.begin(), z.begin(),
+        [a](T X, T Y) {
+            return a * X + Y;
+        });
+}
+
diff --git a/day5/examples/modules/saxpy/with_modules/usesaxpy.cc b/day5/examples/modules/saxpy/with_modules/usesaxpy.cc
new file mode 100644
index 0000000000000000000000000000000000000000..54fd6eb5420189b492dac7b557d7441d14455073
--- /dev/null
+++ b/day5/examples/modules/saxpy/with_modules/usesaxpy.cc
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <array>
+#include <vector>
+#include <span>
+import saxpy;
+
+auto main() -> int
+{
+    using namespace std;
+    const array inp1 { 1., 2., 3., 4., 5. };
+    const array inp2 { 9., 8., 7., 6., 5. };
+    vector outp(inp1.size(), 0.);
+
+    saxpy(10., {inp1}, {inp2}, {outp});
+    for (auto x : outp) cout << x << "\n";
+    cout << ":::::::::::::::::::::\n";
+}
+
diff --git a/day5/examples/ranges/dangling0.cc b/day5/examples/ranges/dangling0.cc
new file mode 100644
index 0000000000000000000000000000000000000000..acc26317f12b687312960a48d75ad58951664ff8
--- /dev/null
+++ b/day5/examples/ranges/dangling0.cc
@@ -0,0 +1,22 @@
+#include <string>
+#include <cxx20ranges>
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+//namespace sr = std::ranges;
+//namespace sv = std::views;
+
+auto get_vec()
+{
+    std::vector v{ 2, 4, -1, 8, 0, 9 };
+    return v;
+}
+
+auto main() -> int
+{
+    auto vec = get_vec();
+    auto iter = sr::min_element(get_vec());
+    std::cout << "Minimum value is " << *iter << "\n";
+}
+
diff --git a/day5/examples/ranges/dangling1.cc b/day5/examples/ranges/dangling1.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cc44e1381b608b12999e0049c9155c53792a5326
--- /dev/null
+++ b/day5/examples/ranges/dangling1.cc
@@ -0,0 +1,19 @@
+#include <span>
+#include <vector>
+#include <iostream>
+#include <cxx20ranges>
+#include <algorithm>
+
+static std::vector u{2, 3, 4, -1, 9};
+static std::vector v{3, 1, 4, 1, 5};
+auto get_vec(int c) -> std::span<int> {
+    return {(c%2 ==0) ? u : v};
+}
+auto main(int argc, char* argv[]) -> int {
+
+    //namespace sr = std::ranges;
+    auto iter = sr::min_element(get_vec(argc));
+
+    std::cout << "Minimum " << *iter << "\n";
+}
+
diff --git a/day5/examples/ranges/gerund.cc b/day5/examples/ranges/gerund.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fa4f397e3283d1a056f0e4cb3b54dfa88d2a9c45
--- /dev/null
+++ b/day5/examples/ranges/gerund.cc
@@ -0,0 +1,23 @@
+#include "range_output.hh"
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <cxx20ranges>
+#include <string>
+
+// namespace sr = std::ranges;
+// namespace sv = std::views;
+
+int main(int argc, char* argv[])
+{
+    using namespace output;
+    if (argc < 2) {
+        std::cerr << "Usage:\n"
+                  << argv[0] << " input_file_name\n";
+        return 1;
+    }
+    auto gerund = [](std::string_view w) { return w.ends_with("ing"); };
+    std::ifstream fin { argv[1] };
+    auto in = sr::istream_view<std::string>(fin);
+    std::cout << (in | sv::filter(gerund)) << "\n";
+}
diff --git a/day5/examples/ranges/ha b/day5/examples/ranges/ha
new file mode 100644
index 0000000000000000000000000000000000000000..c28786308e237b04f8ffbb1798ffd95ad56e5353
--- /dev/null
+++ b/day5/examples/ranges/ha
@@ -0,0 +1,11 @@
+The ranges library is an extension and generalization of the algorithms and iterator libraries that makes them more powerful by making them composable and less error-prone.
+
+The library creates and manipulates range views, lightweight objects that indirectly represent iterable sequences (ranges). Ranges are an abstraction on top of
+
+    [begin, end) iterator pairs, e.g. ranges made by implicit conversion from containers. All algorithms that take iterator pairs now have overloads that accept ranges (e.g ranges::sort)
+    [start, size) counted sequences, e.g. range returned by views::counted
+    [start, predicate) conditionally-terminated sequences, e.g. range returned by views::take_while
+    [start..) unbounded sequences, e.g. range returned by views::iota 
+
+The ranges library includes range algorithms, which are applied to ranges eagerly, and range adaptors, which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated. 
+
diff --git a/day5/examples/ranges/iota.cc b/day5/examples/ranges/iota.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c30566b9901be118afb5c708a182ceb580449d26
--- /dev/null
+++ b/day5/examples/ranges/iota.cc
@@ -0,0 +1,20 @@
+// examples/iota.cc
+#include <iostream>
+#include <cxx20ranges>
+// Compatibility header.
+
+auto main() -> int
+{
+    // namespace sv = std::views;
+    // Uncomment the line above if not using
+    // the compatibility header.
+    for (auto i : sv::iota(1UL)) {
+        if ((i + 1) % 10000UL == 0UL) {
+            std::cout << i << ' ';
+            if ((i + 1) % 100000UL == 0UL)
+                std::cout << '\n';
+            if (i >= 100000000UL)
+                break;
+        }
+    }
+}
diff --git a/day5/examples/ranges/ranges0.cc b/day5/examples/ranges/ranges0.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c81e51477e18365b8b0dbd9eb429907c2c79a310
--- /dev/null
+++ b/day5/examples/ranges/ranges0.cc
@@ -0,0 +1,38 @@
+#include <iostream>
+#include <span>
+#include <vector>
+#include <valarray>
+#include <list>
+#include <array>
+#include <string>
+
+#include <cxx20ranges>
+// Compatibility header in your include path
+// Replace with <ranges> if you only work with
+// g++ or if your version of clang++ already
+// has ranges algorithms implemented.
+
+//    namespace sr = std::ranges;
+//    namespace sv = std::views;
+//  Uncomment the above two lines if you are not using the
+//  compatibility header above.
+
+auto sum(sr::input_range auto&& seq)
+{
+    std::iter_value_t<decltype(seq)> ans{};
+    for (auto x : seq) ans += x;
+    return ans;
+}
+
+int main()
+{
+    using namespace std::string_literals;
+    std::cout << "vector : " << sum(std::vector({ 9,8,7,2 } )) << "\n";
+    std::cout << "list : " << sum(std::list({ 9,8,7,2 } )) << "\n";
+    std::cout << "valarray : " << sum(std::valarray({ 9,8,7,2 } )) << "\n";
+    std::cout << "array : " << sum(std::array<int,4>({ 9,8,7,2 } )) << "\n";
+    std::cout << "array : " << sum(std::array<std::string, 4>({ "9"s,"8"s,"7"s,"2"s } )) << "\n";
+    int A[]{1,2,3};
+    std::cout << "C-array wrapped by span : " << sum(std::span(A)) << "\n";
+}
+
diff --git a/day5/examples/ranges/seqops_range.cc b/day5/examples/ranges/seqops_range.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2d1c7beae7419c351b9be2b55417e3da73c449cc
--- /dev/null
+++ b/day5/examples/ranges/seqops_range.cc
@@ -0,0 +1,50 @@
+#include "range_output.hh"
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <cxx20ranges>
+#include <vector>
+
+int main()
+{
+    using namespace std;
+//  namespace sr = std::ranges;
+    using namespace output;
+    vector v { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    cout << "Vector v = (after initialization): " << v << "\n";
+    if (sr::is_sorted(v))
+        cout << "The sequence is sorted in the increasing order.\n";
+    else
+        cout << "The sequence is not sorted in the increasing order.\n";
+
+    sr::reverse(v);
+    cout << "After std::ranges::reverse: " << v << "\n";
+
+    sr::rotate(v, v.begin() + 3);
+    cout << "After std::rotate by 3" << v << "\n";
+
+    sr::sort(v);
+    cout << "After std::ranges::sort" << v << "\n";
+
+    vector<int> w { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, x, y, z;
+    cout << "Vector w = " << w << "\n";
+
+    vector<int> m;
+    sr::merge(v, w, std::back_inserter(m));
+    cout << "ranges::merge of v and w gives ... : " << m << "\n";
+
+    sr::set_union(v, w, back_inserter(x));
+    cout << "Union of v and w : " << x << "\n";
+
+    sr::set_intersection(w, v, back_inserter(y));
+    cout << "Intersection of w and v : " << y << "\n";
+
+    sr::set_symmetric_difference(v, w, back_inserter(z));
+    cout << "Symmetric difference of v and w : " << z << "\n";
+
+    if (sr::is_permutation(z, v)) {
+        cout << "The above sequence is a permutation of the first sequence printed.\n";
+    } else {
+        cout << "The above sequence is not a permutation of the first sequence printed.\n";
+    }
+}
diff --git a/day5/examples/ranges/trig_views.cc b/day5/examples/ranges/trig_views.cc
new file mode 100644
index 0000000000000000000000000000000000000000..67ec8d7931c2edf3f84096a33fac613d205a72ab
--- /dev/null
+++ b/day5/examples/ranges/trig_views.cc
@@ -0,0 +1,44 @@
+// examples/trig_views.cc
+#include <iostream>
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include <cxx20ranges>
+
+// Compatibility header in your include path
+// Replace with <ranges> if you only work with
+// g++ or if your version of clang++ already
+// has ranges algorithms implemented.
+
+int main()
+{
+//    namespace sr = std::ranges;
+//    namespace sv = std::views;
+//  Uncomment the above two lines if you are not using the
+//  compatibility header above.
+
+    const auto pi = std::acos(-1);
+    constexpr auto npoints = 10'000'00UL;
+    constexpr auto eps = 100 * std::numeric_limits<double>::epsilon();
+    auto to_0_2pi = [=](size_t idx) -> double {
+         return std::lerp(0., 2*pi, idx * 1.0 / npoints);
+    };
+    auto x_to_fx = [ ](double x) -> double {
+         return sin(x) * sin(x) + cos(x) * cos(x) - 1.0;
+    };
+    auto is_bad = [=](double x){ return std::fabs(x) > eps; };
+    auto res = sv::iota(0UL, npoints) | sv::transform(to_0_2pi)
+               | sv::transform(x_to_fx);
+    if (sr::any_of(res, is_bad) ) {
+        std::cerr << "There is at least one input for which the relation does not hold.\n"
+                  << "They are...\n";
+        for (auto bad_res : res | sv::filter(is_bad)) {
+            std::cerr << bad_res << "\n";
+        } 
+    } else {
+        std::cout << "The relation holds for all inputs\n";
+    }
+}
+
+
diff --git a/day5/examples/ranges/trig_views2.cc b/day5/examples/ranges/trig_views2.cc
new file mode 100644
index 0000000000000000000000000000000000000000..94f2e1e40ae39ff8b7eaae08f7c745b11df89204
--- /dev/null
+++ b/day5/examples/ranges/trig_views2.cc
@@ -0,0 +1,34 @@
+// examples/trig_views2.cc
+#include <iostream>
+#include <cxx20ranges>
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+auto main() -> int
+{
+    //namespace sr = std::ranges;
+    //namespace sv = std::views;
+    const auto pi = std::acos(-1);
+    constexpr auto npoints = 100UL;
+    auto is_bad = [=](double x){ return x > 0; };
+    auto res = sv::iota(0UL, npoints)
+               | sv::transform([=](auto idx){ 
+                                   auto output =  std::lerp(0., 2*pi, idx * 1.0 / npoints);
+                                   std::cout << "Mapping " << idx << " to " << output << "\n";
+                                   return output;
+                               } )
+               | sv::transform([ ](auto x)  { 
+                                   auto output = sin(x) * sin(x) - 0.99;
+                                   std::cout << "Input = " << x << "\toutput = " << output << "\n"; 
+                                   return output;
+                               } );
+    std::cout << "Evaluating any_of ...\n";
+    if (sr::any_of(res, is_bad) ) {
+        std::cerr << "There is at least one input for which the relation does not hold.\n";
+    } else {
+        std::cout << "The relation holds for all inputs\n";
+    }
+}
+
+
diff --git a/day5/examples/ranges/views_and_span.cc b/day5/examples/ranges/views_and_span.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a3d3376a144e27eaadf14b488a3ed9c85b4817b4
--- /dev/null
+++ b/day5/examples/ranges/views_and_span.cc
@@ -0,0 +1,25 @@
+// examples/views_and_span.cc
+#include <iostream>
+#include <span>
+#include <cxx20ranges>
+#include <algorithm>
+#include <string>
+#include <iomanip>
+
+auto main(int argc, char * argv[]) -> int
+{
+    std::span args(argv, argc);
+    auto str = [](auto inp) -> std::string_view { return inp; };
+    if (argc < 2) {
+        std::cout << "Usage:\n"
+                  << argv[0] << " some strings in the command line\n";
+        return 1;
+    }
+    //namespace sr = std::ranges;
+    //namespace sv = std::views;
+    auto [first, last] = sr::minmax( args | sv::drop(1) | sv::transform(str) );
+
+    std::cout << "Alphabetically first and last strings in your input are " 
+              << std::quoted(first) << " and " << std::quoted(last) << "\n";
+}
+
diff --git a/day5/examples/spans/main.cc b/day5/examples/spans/main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fc9c2744747168849a20c61d8bca05d171e95716
--- /dev/null
+++ b/day5/examples/spans/main.cc
@@ -0,0 +1,29 @@
+#include <vector>
+#include <valarray>
+#include <iostream>
+#include "spanfunc.hh"
+
+using std::span;
+void elsewhere(double* x, double* y,
+               unsigned N)
+{
+    // Use it when you only have C-style
+    // pointers and sizes
+    std::cout << "adapting C-style arrays: "
+              << compute(span(x, N), span(y, N)) << "\n";
+}
+
+auto main() -> int
+{
+    std::vector x(100UL, 2.3);
+    std::vector y(x.size(), 3.4);
+    // Use it as if it was written for vector!
+    std::cout << "direct: " << compute(x, y) << "\n";
+    std::valarray z(2.3, x.size()); // weird constructor, remember!
+    // Use the same function also for valarrays!
+    std::cout << "two valarrays: " << compute(z, z) << "\n";
+    // Even with a valarray and a vector!
+    std::cout << "valarray and vector : " << compute(x, z) << "\n";
+    elsewhere(x.data(), y.data(), x.size());
+}
+
diff --git a/day5/examples/spans/spanfunc.cc b/day5/examples/spans/spanfunc.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8876cb442b23957916225b222d19772a5dd74def
--- /dev/null
+++ b/day5/examples/spans/spanfunc.cc
@@ -0,0 +1,17 @@
+#include "spanfunc.hh"
+#include <numeric>
+#include <functional>
+
+using std::span;
+using std::transform_reduce;
+using std::plus;
+using std::multiplies;
+// write function in terms of spans
+auto compute(span<const double> u,
+    span<const double> v) -> double
+{
+    return transform_reduce(
+        u.begin(), u.end(),
+        v.begin(), 0., plus<double>{},
+        multiplies<double>{});
+}
diff --git a/day5/examples/spans/spanfunc.hh b/day5/examples/spans/spanfunc.hh
new file mode 100644
index 0000000000000000000000000000000000000000..6d8c8d2385666677556a073bee5ec746740573c0
--- /dev/null
+++ b/day5/examples/spans/spanfunc.hh
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <span>
+
+// write function in terms of spans
+auto compute(std::span<const double> u, std::span<const double> v) -> double;
+
diff --git a/day5/examples/word_count.cc b/day5/examples/word_count.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a209353ae7be0514cfa12908fd2cb933d2e22d3b
--- /dev/null
+++ b/day5/examples/word_count.cc
@@ -0,0 +1,26 @@
+#include <fstream>
+#include <cxx20format>
+#include <cxx20ranges>
+#include <iostream>
+#include <map>
+#include <string>
+
+auto main(int argc, char* argv[]) -> int
+{
+    std::ifstream fin(argv[1]);
+    std::map<std::string, unsigned> freq;
+    std::string s;
+    auto non_alphabetic = [](auto c) { return not isalpha(c); };
+
+    while (fin >> s) {
+        std::string s2;
+        sr::copy(s | sv::drop_while(non_alphabetic)
+                   | sv::reverse
+                   | sv::drop_while(non_alphabetic)
+                   | sv::reverse, std::back_inserter(s2));
+        freq[s2]++;
+    }
+
+    for (auto&& [word, count] : freq)
+        std::cout << fmt::format("{:20}{:4}{:12}\n", word, ':', count);
+}