diff --git a/books/epilight_python_new.pdf b/books/epilight_python_new.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..efcb22cf7fd4e4f71240b27352f09ca6f4ab0213
Binary files /dev/null and b/books/epilight_python_new.pdf differ
diff --git a/labs/08-binary-trees-traversal-exercises.ipynb b/labs/08-binary-trees-traversal-exercises.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..5fec90254b9b06e8fa8617fd896130e7ff269bff
--- /dev/null
+++ b/labs/08-binary-trees-traversal-exercises.ipynb
@@ -0,0 +1,593 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "a6a7c327",
+   "metadata": {},
+   "source": [
+    "NAME:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e14a9e35-e497-4765-8089-95d0db59f82d",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "# UE5 Fundamentals of Algorithms\n",
+    "# Lab 8: Binary trees traversals"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "da448b8a-05e3-4ee6-b3b8-6fa4c41f55b6",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d3c4bf88-8101-42bb-a14d-9e5607b55d57",
+   "metadata": {},
+   "source": [
+    "We will use the following binary tree data structure (unless specified otherwise):"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "2b179632-5d9e-4abd-95c1-abfea9d455df",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "class Node:\n",
+    "    def __init__(self, value):\n",
+    "        self.value = value\n",
+    "        self.left = None\n",
+    "        self.right = None"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1d18a7cb-9003-4d84-a68d-dfbd8202713b",
+   "metadata": {},
+   "source": [
+    "## Exercise 1: Check if a binary tree is balanced"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ac3a3e11-4a8d-416c-8b55-3c6a4137a457",
+   "metadata": {},
+   "source": [
+    "Write an **iterative** function that checks if a binary tree is balanced, i.e. the difference between the heights of the left and right subtrees is at most 1.\n",
+    "\n",
+    "Tips:\n",
+    "- Use af dfs traversal approach (using a stack) using a post-order approach (left, right, and root node)\n",
+    "- For each node, calculate and memorize the current height in a dictionnary\n",
+    "- Check if the current node is balanced, if not return `False`\n",
+    "- Mark the node as visited and store its height\n",
+    "- Return `True` if all the nodes are visited (without an un-balanced situation)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "51a49306-6cb7-4e84-9257-081793657848",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "87a9e0ddfcedc6d476e6774ce0c52278",
+     "grade": false,
+     "grade_id": "cell-9be6329f66aa0822",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_balanced_ite(root):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "556f6692-1e4f-4f55-adbc-cf373402673d",
+   "metadata": {},
+   "source": [
+    "Compare to the following recursive version:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b7fb2e89-b045-4a46-851e-153c64e0de60",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def get_height(node):\n",
+    "    if node is None:\n",
+    "        return -1\n",
+    "    left_height = get_height(node.left)\n",
+    "    right_height = get_height(node.right)\n",
+    "    return max(left_height, right_height) + 1\n",
+    "\n",
+    "def is_balanced(root):\n",
+    "    # un abre vide (None) est équilibré\n",
+    "    if root is None: \n",
+    "        return True\n",
+    "    return is_balanced(root.right) and is_balanced(root.left) and abs(get_height(root.left) - get_height(root.right)) <= 1\n",
+    "\n",
+    "#get_height(racine)\n",
+    "#is_balanced(racine)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "00e2ddec-e259-4f8b-a414-a11051672173",
+   "metadata": {},
+   "source": [
+    "Write tests with both balanced and unbalanced trees."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f90da531-0173-429a-a415-923e7b2bf275",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "9d5e1580d1c78f16d9a187e4f353c99d",
+     "grade": false,
+     "grade_id": "cell-62f1e3032591a590",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "09013922-8606-4298-91e5-02da49a8ced2",
+   "metadata": {},
+   "source": [
+    "## Exercise 2: DFS traversal orders\n",
+    "\n",
+    "Given the following tree, which type of dfs traversal order you may use to return the number in ascending order?\n",
+    "\n",
+    "```\n",
+    "    1\n",
+    "   / \\\n",
+    "  2   5\n",
+    " / \\\n",
+    "3   4\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "afa39767-9b92-4eb7-8a2c-7b59715153da",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def inorder_traversal(root):\n",
+    "    if root is not None:\n",
+    "        inorder_traversal(root.left)\n",
+    "        print(root.value, end=' ')\n",
+    "        inorder_traversal(root.right)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e88833c1-3cf0-4751-bf79-d7ba410a3dd2",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def preorder_traversal(root):\n",
+    "    if root is not None:\n",
+    "        print(root.value, end=' ')\n",
+    "        preorder_traversal(root.left)\n",
+    "        preorder_traversal(root.right)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fdff0e4c-e6f1-4185-b7dc-92aa3f8f7ccb",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def postorder_traversal(root):\n",
+    "    if root is not None:\n",
+    "        postorder_traversal(root.left)\n",
+    "        postorder_traversal(root.right)\n",
+    "        print(root.value, end=' ')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "78fbbaa9-a66f-4edc-ad6d-35364efcf83a",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "8b065502c3c0d81f22e153ccb0bdcf85",
+     "grade": false,
+     "grade_id": "cell-525d556fb7dad98a",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0ab0e8cb-0f07-4df4-a1e1-8934b9fa9de2",
+   "metadata": {},
+   "source": [
+    "Now write the corresponding tree for the 2 other traversal functions to return values in ascending order (i.e. provide a new tree but do not change the functions)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "498cd602-5e9e-456b-b66a-4b289442170f",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "43158bce133c763a801278ce66e04227",
+     "grade": false,
+     "grade_id": "cell-56de47103a5dc76a",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "13dd6b6f-e843-4a92-af0e-2c860d95cf40",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "8f4024dc6f357c7ea8450e3d5c290030",
+     "grade": false,
+     "grade_id": "cell-f407001e56e50590",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "098f76aa-1597-4394-a7d7-564e5e1949cf",
+   "metadata": {},
+   "source": [
+    "## Exercise 3: Check if two binary trees are identical\n",
+    "\n",
+    "```\n",
+    "    1            1\n",
+    "   / \\          / \\\n",
+    "  2   3        2   3\n",
+    "```\n",
+    "\n",
+    "For the example above, it may return `True`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "49aa6fce-c267-4ac1-af06-085ab33cfb4f",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "e3f63d2b59a5d5ccdfcea2a42970fbe7",
+     "grade": false,
+     "grade_id": "cell-20f87de8b31f2a3c",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def check_equal(p, q):\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d34397b0-e505-410f-9edb-75d6f9f35b32",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "p = Node(1)\n",
+    "q = Node(1)\n",
+    "assert check_equal(p, q)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8d65c14b",
+   "metadata": {},
+   "source": [
+    "## Exercise 4: Check if a binary tree has a cycle\n",
+    "\n",
+    "Write a function to determine if a binary tree contains a cycle (i.e. when a node is revisited during traversal)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "3e5a8a2d",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "2b5bfee5cafc6429c7bbe50c6d52bccd",
+     "grade": false,
+     "grade_id": "cell-80c8ab8f6a53a30e",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def has_cycle(node, visited=None, parent=None):\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "83f55a68",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "root = Node(1)\n",
+    "root.left = Node(2)\n",
+    "root.right = Node(3)\n",
+    "root.left.left = Node(4)\n",
+    "root.left.right = Node(5)\n",
+    "\n",
+    "assert not has_cycle(root)\n",
+    "\n",
+    "# add a cycle\n",
+    "root.left.left.right = root\n",
+    "\n",
+    "assert has_cycle(root)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1aa5b552-aaa6-4f97-921e-fcc0135ad485",
+   "metadata": {},
+   "source": [
+    "## Exercise 5: Check if a binary tree is connected\n",
+    "\n",
+    "Write a function to determine if a binary is connected to all the nodes of the tree. Warning: will now use a dictionnary data structure to store the tree."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "8ba8a250-70f7-4ec8-9deb-eea0b3f34ca3",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "T_dict = {\n",
+    "    '0': ['1', '2'],\n",
+    "    '1': ['4', '5'],\n",
+    "    '2': ['3'],\n",
+    "    '4': [],\n",
+    "    '5': [],\n",
+    "    '3': []\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0460d5e5-d9b1-4418-a58b-0e00a481ed67",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "8512f8ddd6ccce216feb0f213417c264",
+     "grade": false,
+     "grade_id": "cell-bc5d0252ee379402",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_connected(T_dict):\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d8298892-488a-482c-98bd-2a16d02f29a6",
+   "metadata": {},
+   "source": [
+    "Write tests for bot a connected and a non-connected tree."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "55ab4951-be83-48ee-a6c5-85d6e73bdf05",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "f4dddcceb5343e7311bee83bd4b4396f",
+     "grade": false,
+     "grade_id": "cell-135d5364fe4568d7",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c06c33fb-661b-4a73-84f7-c19c5c157fae",
+   "metadata": {},
+   "source": [
+    "## Exercise 6: Calculate the diameter of a binary tree\n",
+    "\n",
+    "To find the diameter of a binary tree, you need to compute the longest path between any two nodes in the tree. This path may or may not pass through the root. Here is a way to calculate the diameter:\n",
+    "\n",
+    "1. Calculate the height of the left and right subtrees for each node\n",
+    "2. Calculate the diameter at each node as the height of left subtree + right subtree\n",
+    "3. Traverse the tree and keep track of the max diameter encountered\n",
+    "\n",
+    "Note: we will used the `Node` data structure."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c2595aa9-d477-48c8-9aaa-9bc331930877",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "3bd5c7cf506d5e2c49498570c3fbc2ce",
+     "grade": false,
+     "grade_id": "cell-e54053e5277ec8ad",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e21f200a-ff9b-46af-b504-876c47b80f48",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "root = Node(1)\n",
+    "root.left = Node(2)\n",
+    "root.right = Node(3)\n",
+    "root.left.left = Node(4)\n",
+    "root.left.right = Node(5)\n",
+    "assert diameter(root) == 3 # 3"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.9"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}