diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2D.cpp b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4036014250ae6cf4e559e38cbe534908fe3f81e8
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2D.cpp	
@@ -0,0 +1,14 @@
+#include <iostream>
+#include "Point2D.h"
+
+void Point2D::printCoordinates() {
+    std::cout << "Two coordinates: " << "(" << coord1 << ", " << coord2 << ")" << std::endl;
+}
+
+void CartesianPoint2D::printCoordinates() {
+    std::cout << "Cartesian coordinates: " << "(x=" << coord1 << ", y=" << coord2 << ")" << std::endl;
+}
+
+void PolarPoint2D::printCoordinates() {
+    std::cout << "Polar coordinates: " << "(radius=" << coord1 << ", angle=" << coord2 << ")" << std::endl;
+}
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2D.h b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2D.h
new file mode 100644
index 0000000000000000000000000000000000000000..4332f30d52423c118bcc965e3ac6d885e924b9da
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2D.h	
@@ -0,0 +1,26 @@
+#pragma once
+
+class Point2D {
+protected:
+    int coord1;
+    int coord2;
+public:
+    Point2D(int a, int b) : coord1{a}, coord2{b} {}
+    Point2D() : coord1{0}, coord2{0} {}
+    ~Point2D() {}
+	void printCoordinates();
+};
+
+class CartesianPoint2D : public Point2D {
+public:
+	CartesianPoint2D() : Point2D() {}
+	CartesianPoint2D(int a, int b) : Point2D(a, b) {}
+	void printCoordinates(); 
+};
+
+class PolarPoint2D : public Point2D {
+public:
+	PolarPoint2D() : Point2D() {}
+	PolarPoint2D(int a, int b) : Point2D(a, b) {}
+	void printCoordinates(); 
+};
\ No newline at end of file
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2DVirtual.cpp b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2DVirtual.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1672e7a1e11bcb071b302bbf823c3508dc3e431c
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2DVirtual.cpp	
@@ -0,0 +1,14 @@
+#include <iostream>
+#include "Point2DVirtual.h"
+
+void Point2DVirtual::printCoordinates() {
+    std::cout << "Virtualisation Base two coordinates: " << "(" << coord1 << ", " << coord2 << ")" << std::endl;
+}
+
+void CartesianPoint2DVirtual::printCoordinates() {
+    std::cout << "Virtualisation Cartesian coordinates: " << "(x=" << coord1 << ", y=" << coord2 << ")" << std::endl;
+}
+
+void PolarPoint2DVirtual::printCoordinates() {
+    std::cout << "Virtualisation Polar coordinates: " << "(radius=" << coord1 << ", angle=" << coord2 << ")" << std::endl;
+}
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2DVirtual.h b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2DVirtual.h
new file mode 100644
index 0000000000000000000000000000000000000000..57edf69f0dbe42ac6edd6480253bd494d01267c6
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/Point2DVirtual.h	
@@ -0,0 +1,35 @@
+#pragma once
+
+class Point2DVirtual {
+protected:
+    int coord1 = 0;
+    int coord2 = 0;
+public:
+    Point2DVirtual(int a, int b) : coord1{a}, coord2{b} {}
+    Point2DVirtual() : coord1{0}, coord2{0} {}
+	virtual void printCoordinates();
+    // virtual void printCoordinates() = 0; // If we declare a function as pure virtual,
+                                            // class Point2DVirtual would become
+                                            // an abstract class and it would be impossible
+                                            // to instantiate it - to have objects of that type.
+                                            // Uncomment the line with pure virtual function and
+                                            // comment the line above it.
+                                            // Can you run the program now?
+                                            // How would you overcome this and still have a vector
+                                            // of points using virtualisation to print each their
+                                            // own version of printCoordinates() function?
+};
+
+class CartesianPoint2DVirtual : public Point2DVirtual {
+public:
+	CartesianPoint2DVirtual() : Point2DVirtual() {}
+	CartesianPoint2DVirtual(int a, int b) : Point2DVirtual(a, b) {}
+	void printCoordinates(); 
+};
+
+class PolarPoint2DVirtual : public Point2DVirtual {
+public:
+	PolarPoint2DVirtual() : Point2DVirtual() {}
+	PolarPoint2DVirtual(int a, int b) : Point2DVirtual(a, b) {}
+	void printCoordinates(); 
+};
\ No newline at end of file
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/main.cpp b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..382f66167765cb362ed0f57f7ab4f723d8dcb59d
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_OOP/main.cpp	
@@ -0,0 +1,50 @@
+#include <iostream>
+#include <vector>
+#include "Point2D.h"
+#include "Point2DVirtual.h"
+
+int main() {
+    Point2D point{2, 3};
+    CartesianPoint2D pointC{10, 20};
+    PolarPoint2D pointP{1, 3};
+
+    // Example of polymorphism
+    // Derived classes call their version of the function printCoordinates()
+    // - they override base class' version of the same function
+    point.printCoordinates();
+    pointC.printCoordinates();
+    pointP.printCoordinates();
+
+    // Example of runtime polymorphism - virtualisation
+    // Base class Point2DVirtual has function printCoordinates()
+    // defined as virtual.
+    std::vector<Point2DVirtual*> points;
+
+    points.reserve(12);
+
+    for (int i = 0; i < 12; i++) {
+        if (i % 4 == 0) {
+            points.push_back(new Point2DVirtual);
+        } else if (i % 3 == 0) {
+            points.push_back(new CartesianPoint2DVirtual);
+        } else {
+            points.push_back(new PolarPoint2DVirtual);
+        }
+    }
+    
+    for (int i = 0; i < 12; i++) {
+        // virtualisation method invoked when the functions are called
+        // via pointer to the base class
+        points.at(i)->printCoordinates(); // In this line points.at(i) is of type
+                                    // "pointer to an instance (object) of class Point2dVirtual".
+                                    // We use operator "->" to get the member function
+                                    // printCoordinates() via pointer.
+    }
+    // and remember to deallocate elements of vector points:
+    for (int i = 0; i < 12; i++) {
+        delete points.at(i);
+    }
+    return 0;
+}
+
+//------------------------------------------------------------------------------
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_Pointers/main.cpp b/templates/_folder_Lectures/Lecture 15/parallell_2_Pointers/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..607e615179cd148113e319ae47128dc6ee94afc1
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_Pointers/main.cpp	
@@ -0,0 +1,76 @@
+#include "std_lib_facilities.h"
+
+constexpr int NO_ERROR = 0; // we can have many error codes defined at some place
+                            // in the program to be used as return values of functions
+                            // to inform the caller about the state of the function
+int incrementValues(int n, int* a, int* b);
+
+int main() {
+    // examples of pointer declarations
+    int a{0}; // variable a of type 'int' initialised to value 0
+    int* ptrInt; // variable ptrInt of type 'pointer to integer', not initialised
+
+    cout << "Variable a initial value: " << a << endl;
+    ptrInt = &a; // example of operator '&' - 'address of'
+    // variable ptrInt now contains the address of integer variable a
+    *ptrInt = 10; // example of use of operator '&' - 'content of' / pointer dereferencing
+    // the value stored in variable a is now changed
+    cout << "Variable a current value: " << a << endl;
+
+    // example of using pointers for receiving more than one return value
+    // from a function
+    int firstNum{10};
+    int secondNum{100};
+    int returnStatus;
+    cout << "Initial values, before calling incrementValues:" << endl
+        << "firstNum: " << firstNum << "   secondNum: " << secondNum << endl;
+    returnStatus = incrementValues(5, &firstNum, &secondNum);
+    cout << "After calling incrementValues:" << endl
+        << "firstNum: " << firstNum << "   secondNum: " << secondNum << endl; 
+    if (returnStatus == NO_ERROR) { // example how we can use return value of the function
+                                    // to pass info on error or exception (much C-like style)
+        cout << "incrementValues run with no errors." << endl;
+    }
+
+    // example of dynamical allocation of matrix elements (Assignment 8)
+    const int matrixSize{3};
+    int** matrix;
+    matrix = new int*[matrixSize]; // Variable matrix is a dynamically allocated array of
+                                // matrixSize pointers to pointers to integer variables
+    for (int i = 0; i < matrixSize; i++) {
+        matrix[i] = new int[matrixSize]; // Each element of dynamically allocated matrix
+                                        // is assigned a value of a pointer to a dynamically
+                                        // allocated array of matrixSize integers
+        // *(matrix + i) = new int[matrixSize]; // equivalent to: matrix[i] = new int[matrixSize];
+    }
+    for (int i = 0; i < matrixSize; i++) {
+        for (int j = 0; j < matrixSize; j++) {
+            matrix[i][j] = i+j;
+        }
+    }
+    // write the values of the matrix and check if they are correct (row+column)
+    for (int i = 0; i < matrixSize; i++) {
+        for (int j = 0; j < matrixSize; j++) {
+            cout << "m[" << i << "][" << j << "] = " << matrix[i][j] << "  ";
+        }
+        cout << endl;
+    }
+
+    // remember to deallocate memory with operator delete[]
+    // for each allocation with new[], there has to be a corresponding delete[]
+    for (int i = 0; i < matrixSize; i++) {
+        delete[] matrix[i];
+    }
+    delete[] matrix;
+
+    return 0;
+}
+
+int incrementValues(int n, int* a, int* b) {
+    for (int i = 0; i < n; i++) {
+        (*a)++;
+        (*b)++;
+    }
+
+    return NO_ERROR;
+}
\ No newline at end of file
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/Game.txt b/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/Game.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0ea13ddd5eb67e23ba523c607b545a31a34cfee1
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/Game.txt	
@@ -0,0 +1 @@
+100 Mitsuko
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/StartPosition.txt b/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/StartPosition.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6534e8b8ee267de76116c5b61e637bf263d069f6
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/StartPosition.txt	
@@ -0,0 +1 @@
+(5, 10)
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/main.cpp b/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4e5b974c1cdc1dff3b8ee80e032fe5ad2d583f4b
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_Streams/main.cpp	
@@ -0,0 +1,46 @@
+#include <iostream>
+#include <fstream>
+#include <filesystem>
+
+constexpr std::string config = "Game.txt"; 
+
+class Point2D {
+    int x;
+    int y;
+public:
+    Point2D() : x{0}, y{0} {}
+    Point2D(int a, int b) : x{a}, y{b} {}
+    friend std::ostream& operator<<(std::ostream& outstream, const Point2D& pt);
+};
+
+std::ostream& operator<<(std::ostream& outstream, const Point2D& pt) {
+    outstream << "(" << pt.x << ", " << pt.y << ")" << std::endl;
+    return outstream;
+}
+
+int main() {
+    std::filesystem::path fileName{"Game.txt"};
+    std::ifstream inStream{fileName};
+    int readScore;
+    std::string readPlayerName{""};
+    
+    if (inStream.is_open()) {
+        inStream >> readScore >> readPlayerName;
+    }
+    std::cout << "Read points: " << readScore << std::endl 
+        << "Read Player Name: " << readPlayerName << std::endl;
+
+    // We can also use function getline() from the standard library
+    // to read the whole line from the file:
+    //std::string line{""};
+    //std::getline(inStream, line);
+    //std::cout << "Read the line: " << line << std::endl;
+
+    // example of calling operator << for a variable of a class type
+    // (see the class and function definitions at the top of this file)
+    Point2D startPos{5, 10};
+    std::ofstream outStreamStart{"StartPosition.txt"};
+    outStreamStart << startPos;
+
+    return 0;
+}
\ No newline at end of file
diff --git a/templates/_folder_Lectures/Lecture 15/parallell_2_Templates/main.cpp b/templates/_folder_Lectures/Lecture 15/parallell_2_Templates/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7c29d3c4fd404cb99efac228901bb8587a44b3e7
--- /dev/null
+++ b/templates/_folder_Lectures/Lecture 15/parallell_2_Templates/main.cpp	
@@ -0,0 +1,87 @@
+#include <iostream>
+#include <stack>
+#include <queue>
+
+template<typename T>
+class Qubit {
+    T x;
+    T y;
+    T z;
+public:
+    Qubit(T a, T b, T c) : x{a}, y{b}, z{c} {}
+    void PrintQubit() {
+        std::cout << "This Qubit:" << std::endl 
+            << "X: " << x << std::endl
+            << "Yi: " << y << std::endl
+            << "Z: " << z << std::endl;
+    } 
+};
+
+template<typename T>
+void Print3Times(T& val) {
+    std::cout << "Printing " << val << " " << "3 times:" << std::endl;
+    for (int i = 0; i < 3; i++) {
+        std::cout << val << " ";
+    }
+    std::cout << std::endl;    
+}
+
+template<typename T, int N>
+void PrintNTimes(T& val) {
+    std::cout << "Printing " << val << " " << N << " times:" << std::endl;
+    for (int i = 0; i < N; i++) {
+        std::cout << val << " ";
+    }
+    std::cout << std::endl;
+}
+
+class Point2D {
+    int x;
+    int y;
+public:
+    Point2D() : x{0}, y{0} {}
+    Point2D(int a, int b) : x{a}, y{b} {}
+    friend std::ostream& operator<<(std::ostream& outstream, const Point2D& pt);
+};
+
+std::ostream& operator<<(std::ostream& outstream, const Point2D& pt) {
+    outstream << "(" << pt.x << ", " << pt.y << ")" << std::endl;
+    return outstream;
+}
+
+int main() {
+    Qubit<int> qubit1{0, 0, 1};
+    Qubit<double> qubit2{0.7, 0.7, 0.7};
+
+    qubit1.PrintQubit();
+    qubit2.PrintQubit();
+
+    int num1{10};
+    int num2{5};
+    Print3Times(num1); // example of template argument deduction
+    PrintNTimes<int, 3>(num2);
+    Point2D point{2, 3};
+    PrintNTimes<Point2D, 2>(point); // we need to have operator<<() overloaded for Point2D!
+
+    // STL data structures
+    // The most used container / data structure from STL library is by far vector<>.
+    // We have already seen many examples of its use so here comes an example with
+    // stack and queue data structures. Stack is a LIFO (Last In First Out) and queue
+    // a FIFO (First In First Out) data structure. This is reflected in how method pop()
+    // removes elements from each of them as illustrated in the example below:
+    // You don't have to know all of the data structures from STL! stack and queue are
+    // given just as examples.
+    std::stack<int> stack1;
+    std::queue<int> queue1;
+
+    for (int i = 0; i < 10; i++) {
+        stack1.push(i);
+        queue1.push(100*i);
+    }
+    while (!(stack1.empty() || queue1.empty())) {
+        std::cout << stack1.top() << std::endl;
+        std::cout << queue1.front() << std::endl;
+        stack1.pop();
+        queue1.pop(); 
+    }
+}
\ No newline at end of file