From c2fd0506069997cf2c28114fa0a11f360b765688 Mon Sep 17 00:00:00 2001
From: Mirko Birbaumer <mirko.birbaumer@hslu.ch>
Date: Sat, 17 Sep 2022 15:18:46 +0000
Subject: [PATCH] Added notebook on colab

---
 ...upyter Notebook - Introduction Colab.ipynb | 1372 +++++++++++++++++
 1 file changed, 1372 insertions(+)
 create mode 100644 notebooks/Preliminaries_Numpy_Pandas/Jupyter Notebook - Introduction Colab.ipynb

diff --git a/notebooks/Preliminaries_Numpy_Pandas/Jupyter Notebook - Introduction Colab.ipynb b/notebooks/Preliminaries_Numpy_Pandas/Jupyter Notebook - Introduction Colab.ipynb
new file mode 100644
index 0000000..f1aff13
--- /dev/null
+++ b/notebooks/Preliminaries_Numpy_Pandas/Jupyter Notebook - Introduction Colab.ipynb	
@@ -0,0 +1,1372 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "UoQjqjBOIzfG"
+   },
+   "source": [
+    "# Colaboratory"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "BcXbc54tbXq7"
+   },
+   "source": [
+    "## Introduction"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "fPP3Zw5iV2DP"
+   },
+   "source": [
+    "\n",
+    "\n",
+    "Some important links to keep open during this course – open these tabs **now**!:\n",
+    "\n",
+    "- [TF documentation](https://www.tensorflow.org/api_docs/python/tf) : Use the search box (top right) to get documentation on Tensorflow's rich API.\n",
+    "\n",
+    "\n",
+    "---\n",
+    "\n",
+    "Colaboratory (Colab) is a Jupyter notebook environment which allows you to work with data and code in an interactive manner. You can decide where you want to run your code:\n",
+    "\n",
+    "*   Using a hosted runtime provided by Google (**default**)\n",
+    "*   Locally using your own machine and resources\n",
+    "\n",
+    "It supports Python 3 and comes with a set of pre-installed libraries like Tensorflow and Matplotlib but also gives you the option to install more libraries on demand. The resulting notebooks can be shared in a straightforward way.\n",
+    "\n",
+    "Caveats:\n",
+    "\n",
+    "*   The virtual machines used for the runtimes are **ephemeral** so make sure to save your data in a persistent location like locally (downloading), in the Google Cloud Storage or Google Drive.\n",
+    "*   The service is free of use but the performance of default runtimes can be insufficient for your purposes.\n",
+    "*  You have the option to select a runtime with GPU or TPU support.\n",
+    "*  \"Colaboratory is intended for interactive use. Long-running background computations, particularly on GPUs, may be stopped. [...] We encourage users who wish to run continuous or long-running computations through Colaboratory’s UI to use a local runtime.\" - See [Colaboratory FAQ](https://research.google.com/colaboratory/faq.html \"Colaboratory FAQ\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "iDbiROodhaFQ"
+   },
+   "source": [
+    "**Getting started**\n",
+    "\n",
+    "1.   Connect to a runtime now by clicking `connect` in the top right corner if you don't already see a green checkmark there.\n",
+    "2.   To get a better overview you might want to activate the *Table of contents* by clicking on the arrow on the left."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "M54Z135xV2DW"
+   },
+   "source": [
+    "### Important shortcuts\n",
+    "\n",
+    "Action | Colab Shortcut | Jupyter Shortcut\n",
+    "---|---|---\n",
+    "Executes current cell | `<CTRL-ENTER>` | `<CTRL-ENTER>`\n",
+    "Executes current cell and moves to next cell | `<SHIFT-ENTER>` | `S<HIFT-ENTER>`\n",
+    "Executes current selection | `<CTRL-SHIFT-ENTER>` | `N/A`\n",
+    "Insert cell above | `<CTRL-M> <A>` | `<A>`\n",
+    "Append cell below | `<CTRL-M> <B>` | `<B>`\n",
+    "Shows searchable command palette | `<CTRL-SHIFT-P>` | `<CTRL-SHIFT-P>`\n",
+    "Convert cell to code | `<CTRL-M> <Y>` | `<Y>`\n",
+    "Convert cell to Markdown | `<CTRL-M> <M>` | `<M>`\n",
+    "Autocomplete (on by default) | `<CTRL+SPACE>` | `<TAB>`\n",
+    "Goes from edit to \"command\" mode | `<ESC>` | `<ESC>`\n",
+    "Goes from \"command\" to edit mode | `<ENTER>` | `<ENTER>`\n",
+    "Show keyboard shortcuts | `<CTRL-M> <H>` | `<H>`\n",
+    "<p align=\"center\"><b>Note:</b> On OS X you can use `<COMMAND>` instead of `<CTRL>`</p>\n",
+    "\n",
+    "Give it a try!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "iJ4YliVgZNCq",
+    "outputId": "a601b693-3213-4b75-e5db-2d0e9de22b64"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Hello world!\n"
+     ]
+    }
+   ],
+   "source": [
+    "# YOUR ACTION REQUIRED:\n",
+    "# Execute this cell first using <CTRL-ENTER> and then using <SHIFT-ENTER>.\n",
+    "# Note the difference in which cell is selected after execution.\n",
+    "print('Hello world!')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "U-B6-3lmkMwJ"
+   },
+   "source": [
+    "You can also only execute one single statement in a cell."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 51
+    },
+    "id": "IprMQ_z8kOsA",
+    "outputId": "855c699a-efa7-4d68-fbf4-e9a316d50fe2"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Only print this line.\n",
+      "Avoid printing this line.\n"
+     ]
+    }
+   ],
+   "source": [
+    "# YOUR ACTION REQUIRED:\n",
+    "# Execute only the first print statement by selecting the first line and pressing\n",
+    "# <CTRL-SHIFT-ENTER>.\n",
+    "print('Only print this line.')\n",
+    "print('Avoid printing this line.')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "UPQzxvqbMXqr"
+   },
+   "source": [
+    "### Importing TensorFlow"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "rScwW1Q69xJ-"
+   },
+   "source": [
+    "We'll be using **TensorFlow 2.3.0** in this course. This is the default, but for the time being we still need to activate it with the Colab-specific `%tensorflow_version` magic."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "id": "Ys4hO5MtkhCC"
+   },
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "UsageError: Line magic function `%tensorflow_version` not found.\n"
+     ]
+    }
+   ],
+   "source": [
+    "%tensorflow_version  "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 35
+    },
+    "id": "n_J1HPc4kpbl",
+    "outputId": "52b55281-1601-4e55-fc5e-7f2671b7cf14"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'2.1.0'"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# Include basic dependencies and display the tensorflow version.\n",
+    "import tensorflow as tf\n",
+    "tf.__version__"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "1uKqdyHFB8NY"
+   },
+   "source": [
+    "### Running shell commands\n",
+    "\n",
+    "You can run shell commands directly in Colab: simply prepend the command with a **!**."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 51
+    },
+    "id": "FY3pksK4V2DY",
+    "outputId": "962c2489-0095-4718-c090-fb5fccabfc55"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/work/hslu-deep-learning/notebooks/Block 3\n",
+      "'Exercises Block 3 - Training and Optimizing Neural Networks.ipynb'\n",
+      "'Jupyter Notebook Block 3 - Training and Optimizing Neural Networks.ipynb'\n",
+      "'Jupyter Notebook - Introduction Colab.ipynb'\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Print the current working directory and list all files in it.\n",
+    "!pwd\n",
+    "!ls"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 412
+    },
+    "id": "8BbKSuKslVaI",
+    "outputId": "1707154b-d8d1-4cef-8363-e6afc747e8ee"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Collecting qrcode\n",
+      "  Downloading qrcode-6.1-py2.py3-none-any.whl (31 kB)\n",
+      "Requirement already satisfied: six in /opt/conda/lib/python3.7/site-packages (from qrcode) (1.14.0)\n",
+      "Installing collected packages: qrcode\n",
+      "Successfully installed qrcode-6.1\n"
+     ]
+    },
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAASIAAAEiAQAAAAB1xeIbAAABj0lEQVR4nO2ZQU6FMBRFz7MkDkviAlwK3Zlbo0txASZ0aAK5Dlr06x/o5P9iaQdNgZNw83Jp3i0mfh/x4Q8QdKpTnepUp45OWRkDkAYg7XdCVV2noCZJ0gJmIwBOkqTv1P11nYJKxePSsuVV+Qwq6zoZ5a7bzkPoap6y4N/trm88L7VvK15AAgHoc1VN14moaGZmI1hIj7LAltuc2rqaprLvvzyuODr03fXHVd8CZSENeWLSigXAAlv3/R2o+LwC/t2IZqY5mUEasFBXV9MUOUJNC5AT1QKa/Qr4tYSu+ajq/zdVao9XCbKTVvZJ6rW/IfUZXbdBMYBIIwKnyy7/qOpboKTFZY9bAIgjQDLTXFVX21T2/e5xtyqObjX8Vh5Mcx1dZ6DKnpNLnJ4AvyDYEKyDauk6E7WfY9rL64AFXNl9autqmRp+XCuOGNGAOL7V03VGyoIvLSfkk51j6GqR2rNV/m/lpBl30eTnpr/39zeh9myVh9st779SVq/9rairc8zLyfX/tZ3qVKc61Qr1AeMHwb8M15tKAAAAAElFTkSuQmCC\n",
+      "text/plain": [
+       "<qrcode.image.pil.PilImage at 0x7f4d48194410>"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# Especially useful: Installs new packages.\n",
+    "!pip install qrcode\n",
+    "import qrcode\n",
+    "qrcode.make('Colab rocks!')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "ywxYXQ-lCc2_"
+   },
+   "source": [
+    "**Autocompletion and docstrings**\n",
+    "\n",
+    "Jupyter shows possible completions of partially typed\n",
+    "commands.\n",
+    "\n",
+    "Try it for yourself by displaying all available `tf.` methods that start with `one`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "a_jmV9woV2Db",
+    "outputId": "ea99ad25-965c-4101-d4a7-e0a0cf8a19d0"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<function tensorflow.python.ops.array_ops.one_hot(indices, depth, on_value=None, off_value=None, axis=None, dtype=None, name=None)>"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# YOUR ACTION REQUIRED:\n",
+    "# Set the cursor to after tf.one and press <CTRL-SPACE>.\n",
+    "tf.one_hot #tf.one"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "PuBe6L8WOWuS"
+   },
+   "source": [
+    "In addition, you can also display docstrings to see the function signature and possible parameters."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "hPiM64eaOi2y",
+    "outputId": "97d92f6f-7e97-4e8c-b6f5-e6632a8ab71c"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<tf.Tensor: shape=(3,), dtype=int32, numpy=array([2, 2, 3], dtype=int32)>"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# YOUR ACTION REQUIRED:\n",
+    "# Complete the command to \"maximum\" and then add the opening bracket \"(\" to see\n",
+    "# the function documentation.\n",
+    "#tf.maximum()\n",
+    "tf.maximum([1, 2, 3], [2, 2, 2]) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "NK1yV3Ye0pbC"
+   },
+   "source": [
+    "Alternatively, you might also inspect function details with docstrings if available by appending a \"?\"."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "id": "P-IF1l5u0MLT"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[0;31mSignature:\u001b[0m \u001b[0mtf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmaximum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+       "\u001b[0;31mDocstring:\u001b[0m\n",
+       "Returns the max of x and y (i.e. x > y ? x : y) element-wise.\n",
+       "\n",
+       "*NOTE*: `math.maximum` supports broadcasting. More about broadcasting\n",
+       "[here](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)\n",
+       "\n",
+       "Args:\n",
+       "  x: A `Tensor`. Must be one of the following types: `bfloat16`, `half`, `float32`, `float64`, `int32`, `int64`.\n",
+       "  y: A `Tensor`. Must have the same type as `x`.\n",
+       "  name: A name for the operation (optional).\n",
+       "\n",
+       "Returns:\n",
+       "  A `Tensor`. Has the same type as `x`.\n",
+       "\u001b[0;31mFile:\u001b[0m      /opt/conda/lib/python3.7/site-packages/tensorflow_core/python/ops/gen_math_ops.py\n",
+       "\u001b[0;31mType:\u001b[0m      function\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "tf.maximum?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "-wBzGaDMaCg2"
+   },
+   "source": [
+    "**Note:** This also works for any other type of object as can be seen below."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "id": "nLXoW6IXZEvP"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[0;31mType:\u001b[0m        dict\n",
+       "\u001b[0;31mString form:\u001b[0m {'key0': 'Tensor', 'key1': 'Flow'}\n",
+       "\u001b[0;31mLength:\u001b[0m      2\n",
+       "\u001b[0;31mDocstring:\u001b[0m  \n",
+       "dict() -> new empty dictionary\n",
+       "dict(mapping) -> new dictionary initialized from a mapping object's\n",
+       "    (key, value) pairs\n",
+       "dict(iterable) -> new dictionary initialized as if via:\n",
+       "    d = {}\n",
+       "    for k, v in iterable:\n",
+       "        d[k] = v\n",
+       "dict(**kwargs) -> new dictionary initialized with the name=value pairs\n",
+       "    in the keyword argument list.  For example:  dict(one=1, two=2)\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "test_dict = {'key0': 'Tensor', 'key1': 'Flow'}\n",
+    "test_dict?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "_mahgn1AHL61"
+   },
+   "source": [
+    "## Runtimes\n",
+    "\n",
+    "As noted in the introduction above, Colab provides multiple runtimes with different hardware accelerators:\n",
+    "\n",
+    "*   CPU (default)\n",
+    "*   GPU\n",
+    "*   TPU\n",
+    "\n",
+    "which can be selected by choosing the `\"Runtime\"` tab above and then `\"Change runtime type\"`.\n",
+    "\n",
+    "Please be aware that selecting a new runtime will assign a new virtual machine (VM).\n",
+    "In general, assume that any changes you make to the VM environment including data storage are **ephemeral**. Particularly, this might require to **execute previous cells again** as their content is unknown to a new runtime otherwise. \n",
+    "\n",
+    "Let's take a closer look at one of such provided VMs.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "whv1zmERgI5v"
+   },
+   "source": [
+    "Once we have been assigned a runtime we can inspect it further."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "AwLSimGKgHFd",
+    "outputId": "2617a190-93d9-4102-e1a5-ac5078a980a9"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      " 14:31:31 up 4 days,  5:23,  0 users,  load average: 0.38, 0.97, 0.88\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Display how long the system has been running.\n",
+    "!uptime"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "f69GlgeggRED"
+   },
+   "source": [
+    "As can be seen, the machine has been allocated just very recently for our purposes.\n",
+    "\n",
+    "**VM specifications**"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 547
+    },
+    "id": "AAXhttijkq8P",
+    "outputId": "b0b9b8c4-1a7a-4bb4-f111-d81fc233210c"
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "              total        used        free      shared  buff/cache   available\n",
+      "Mem:            47G        5.7G         10G        2.2M         31G         41G\n",
+      "Swap:            0B          0B          0B\n",
+      "----------------------------------------------------------------------\n",
+      "Architecture:        x86_64\n",
+      "CPU op-mode(s):      32-bit, 64-bit\n",
+      "Byte Order:          Little Endian\n",
+      "CPU(s):              16\n",
+      "On-line CPU(s) list: 0-15\n",
+      "Thread(s) per core:  1\n",
+      "Core(s) per socket:  1\n",
+      "Socket(s):           16\n",
+      "NUMA node(s):        1\n",
+      "Vendor ID:           GenuineIntel\n",
+      "CPU family:          6\n",
+      "Model:               61\n",
+      "Model name:          Intel Core Processor (Broadwell, IBRS)\n",
+      "Stepping:            2\n",
+      "CPU MHz:             2194.916\n",
+      "BogoMIPS:            4389.83\n",
+      "Virtualization:      VT-x\n",
+      "Hypervisor vendor:   KVM\n",
+      "Virtualization type: full\n",
+      "L1d cache:           32K\n",
+      "L1i cache:           32K\n",
+      "L2 cache:            4096K\n",
+      "NUMA node0 CPU(s):   0-15\n",
+      "Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl cpuid tsc_known_freq pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti ssbd ibrs ibpb tpr_shadow vnmi flexpriority ept vpid fsgsbase bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt arat md_clear\n",
+      "----------------------------------------------------------------------\n",
+      "/bin/sh: 1: nvidia-smi: not found\n",
+      "/bin/sh: 1: nvidia-smi: not found\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Display available and used memory.\n",
+    "!free -h\n",
+    "print(\"-\"*70)\n",
+    "# Display the CPU specification.\n",
+    "!lscpu\n",
+    "print(\"-\"*70)\n",
+    "# Display the GPU specification (if available).\n",
+    "!(nvidia-smi | grep -q \"has failed\") && echo \"No GPU found!\" || nvidia-smi "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "bqCA9-VDIjsu"
+   },
+   "source": [
+    "## Plotting\n",
+    "\n",
+    "The notebook environment also provides options to visualize and interact with data.\n",
+    "\n",
+    "We'll take a short look at the plotting/visualization libraries Matplotlib and Altair."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "1iJfoQ86AsfO"
+   },
+   "source": [
+    "### Matplotlib\n",
+    "\n",
+    "Matplotlib is one of the most famous Python plotting libraries and can be used to plot results within a cell's output (see [Matplotlib Introduction](https://matplotlib.org/users/intro.html \"Matplotlib Introduction\")).\n",
+    "\n",
+    "Let's try to plot something with it."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 286
+    },
+    "id": "gyk4SEk_V2DW",
+    "outputId": "7120223a-a25d-416c-defc-d7e5cb30c334"
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<matplotlib.collections.PathCollection at 0x7f4bec110710>"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<Figure size 432x288 with 1 Axes>"
+      ]
+     },
+     "metadata": {
+      "needs_background": "light"
+     },
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# Display the Matplotlib outputs within a cell's output. \n",
+    "%matplotlib inline\n",
+    "import numpy as np\n",
+    "from matplotlib import pyplot\n",
+    "\n",
+    "# Create a randomized scatterplot using matplotlib.\n",
+    "x = np.random.rand(100).astype(np.float32)\n",
+    "noise = np.random.normal(scale=0.3, size=len(x))\n",
+    "y = np.sin(x * 7) + noise\n",
+    "pyplot.scatter(x, y)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "lhUudwcUafIm"
+   },
+   "source": [
+    "### Altair\n",
+    "\n",
+    "Another declarative visualization library for Python is Altair (see [Altair: Declarative Visualization in Python](https://altair-viz.github.io/)).\n",
+    "\n",
+    "Try to zoom in/out and to hover over individual data points in the resulting plot below."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 368
+    },
+    "id": "uO3MmbhbIw_t",
+    "outputId": "ed43ddf2-7d39-4310-ce85-65bd3bc87486"
+   },
+   "outputs": [
+    {
+     "ename": "ModuleNotFoundError",
+     "evalue": "No module named 'vega_datasets'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-20-3e82446dd3d7>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# Load an example dataset.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mvega_datasets\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mcars\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcars\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;31m# Plot the dataset, referencing dataframe column names.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'vega_datasets'"
+     ]
+    }
+   ],
+   "source": [
+    "# Load an example dataset.\n",
+    "from vega_datasets import data\n",
+    "cars = data.cars()\n",
+    "\n",
+    "# Plot the dataset, referencing dataframe column names.\n",
+    "import altair as alt\n",
+    "alt.Chart(cars).mark_point().encode(\n",
+    "    x='Horsepower',\n",
+    "    y='Miles_per_Gallon',\n",
+    "    color='Origin',\n",
+    "    tooltip=['Name', 'Origin', 'Horsepower', 'Miles_per_Gallon']\n",
+    "    ).interactive()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "cBUraBMAHE0J"
+   },
+   "source": [
+    "## Notebook Magics\n",
+    "\n",
+    "The IPython and Colab environment support built-in magic commands called magics (see: [IPython - Magics](https://ipython.readthedocs.io/en/stable/interactive/magics.html)).\n",
+    "\n",
+    "In addition to default Python, these commands might be handy for example when it comes to interacting directly with the VM or the Notebook itself.\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "KO1K1UnIfU0u"
+   },
+   "source": [
+    "### Cell magics\n",
+    "\n",
+    "Cell magics define a mode for a complete cell and are prefixed with **%%**.\n",
+    "\n",
+    "Examples include:\n",
+    "\n",
+    "*  **%%bash** or **%%sh**\n",
+    "* **%%html**\n",
+    "* **%%javascript**\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 207
+    },
+    "id": "2qT4YGbOQ9FG",
+    "outputId": "09778496-9cd0-4a59-b5e4-9ba9205a8332"
+   },
+   "outputs": [],
+   "source": [
+    "%%sh\n",
+    "echo \"This is a shell script!\"\n",
+    "# List all running VM processes.\n",
+    "ps -ef\n",
+    "echo \"Done\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 38
+    },
+    "id": "qUSc9sT2JskX",
+    "outputId": "743ca85b-35ed-4df4-ba58-c4fc0c8cc06c"
+   },
+   "outputs": [],
+   "source": [
+    "# Embed custom HTML directly into a cell's output.\n",
+    "%%html\n",
+    "<marquee>HTML rocks</marquee>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "Uy0j4iJ5d8v3"
+   },
+   "source": [
+    "### Line magics \n",
+    "\n",
+    "You can also make use of line magics which can be inserted anywhere at the beginning of a line inside a cell and need to be prefixed with **%**.\n",
+    "\n",
+    "Examples include:\n",
+    "\n",
+    "\n",
+    "*   **%time** - display the required time to execute the current line\n",
+    "*   **%cd** - change the current working directory\n",
+    "*   **%pdb** - invoke an interactive Python debugger\n",
+    "* **%lsmagic** - list all available line magic and cell magic functions\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "mrdhMGsyN2Gl"
+   },
+   "source": [
+    "For example, if you want to find out how long one specific line requires to be executed you can just prepend **%time**.\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 102
+    },
+    "id": "Kz0d1QoINx95",
+    "outputId": "e356539c-ac9f-40d1-de36-03fcf8004b9d"
+   },
+   "outputs": [],
+   "source": [
+    "n = 1000000\n",
+    "%time list1 = [i for i in range(n)]\n",
+    "print(\"\")\n",
+    "%time list2 = [i for i in range(int(n/2))]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "Y_Q3lleVPMVJ"
+   },
+   "source": [
+    "**Note:** Some line magics like **%time** can also be used for complete cells by writing **%%time**."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 51
+    },
+    "id": "LCIrCKs9a1eu",
+    "outputId": "3c85e834-d2fd-4f83-9741-eb89878cd255"
+   },
+   "outputs": [],
+   "source": [
+    "%%time\n",
+    "n = 1000000\n",
+    "list1 = [i for i in range(n)]\n",
+    "list2 = [i for i in range(int(n/2))]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "BGurTn7rVH_I"
+   },
+   "source": [
+    "## Data handling\n",
+    "\n",
+    "There are multiple ways to provide data to a Colabs's VM environment.\n",
+    "> **Note:** This section only applies to Colab.\n",
+    "> Jupyter has a file explorer and other options for data handling.\n",
+    "\n",
+    "The options include:\n",
+    "*   Uploading files from the local file system.\n",
+    "* Connecting to Google Cloud Storage (explained below).\n",
+    "*   Connecting to Google Drive (see: [Snippets: Drive](https://colab.sandbox.google.com/notebooks/snippets/drive.ipynb); will be used in the next Colabs)."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "Zdb5RpNmxoJl"
+   },
+   "source": [
+    "**Uploading files from the local file system**"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 157,
+     "resources": {
+      "http://localhost:8080/nbextensions/google.colab/files.js": {
+       "data": "Ly8gQ29weXJpZ2h0IDIwMTcgR29vZ2xlIExMQwovLwovLyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKLy8geW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgovLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKLy8KLy8gICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKLy8KLy8gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQovLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAovLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KLy8gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAovLyBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCi8qKgogKiBAZmlsZW92ZXJ2aWV3IEhlbHBlcnMgZm9yIGdvb2dsZS5jb2xhYiBQeXRob24gbW9kdWxlLgogKi8KKGZ1bmN0aW9uKHNjb3BlKSB7CmZ1bmN0aW9uIHNwYW4odGV4dCwgc3R5bGVBdHRyaWJ1dGVzID0ge30pIHsKICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpOwogIGVsZW1lbnQudGV4dENvbnRlbnQgPSB0ZXh0OwogIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHN0eWxlQXR0cmlidXRlcykpIHsKICAgIGVsZW1lbnQuc3R5bGVba2V5XSA9IHN0eWxlQXR0cmlidXRlc1trZXldOwogIH0KICByZXR1cm4gZWxlbWVudDsKfQoKLy8gTWF4IG51bWJlciBvZiBieXRlcyB3aGljaCB3aWxsIGJlIHVwbG9hZGVkIGF0IGEgdGltZS4KY29uc3QgTUFYX1BBWUxPQURfU0laRSA9IDEwMCAqIDEwMjQ7CgpmdW5jdGlvbiBfdXBsb2FkRmlsZXMoaW5wdXRJZCwgb3V0cHV0SWQpIHsKICBjb25zdCBzdGVwcyA9IHVwbG9hZEZpbGVzU3RlcChpbnB1dElkLCBvdXRwdXRJZCk7CiAgY29uc3Qgb3V0cHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG91dHB1dElkKTsKICAvLyBDYWNoZSBzdGVwcyBvbiB0aGUgb3V0cHV0RWxlbWVudCB0byBtYWtlIGl0IGF2YWlsYWJsZSBmb3IgdGhlIG5leHQgY2FsbAogIC8vIHRvIHVwbG9hZEZpbGVzQ29udGludWUgZnJvbSBQeXRob24uCiAgb3V0cHV0RWxlbWVudC5zdGVwcyA9IHN0ZXBzOwoKICByZXR1cm4gX3VwbG9hZEZpbGVzQ29udGludWUob3V0cHV0SWQpOwp9CgovLyBUaGlzIGlzIHJvdWdobHkgYW4gYXN5bmMgZ2VuZXJhdG9yIChub3Qgc3VwcG9ydGVkIGluIHRoZSBicm93c2VyIHlldCksCi8vIHdoZXJlIHRoZXJlIGFyZSBtdWx0aXBsZSBhc3luY2hyb25vdXMgc3RlcHMgYW5kIHRoZSBQeXRob24gc2lkZSBpcyBnb2luZwovLyB0byBwb2xsIGZvciBjb21wbGV0aW9uIG9mIGVhY2ggc3RlcC4KLy8gVGhpcyB1c2VzIGEgUHJvbWlzZSB0byBibG9jayB0aGUgcHl0aG9uIHNpZGUgb24gY29tcGxldGlvbiBvZiBlYWNoIHN0ZXAsCi8vIHRoZW4gcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhlIHByZXZpb3VzIHN0ZXAgYXMgdGhlIGlucHV0IHRvIHRoZSBuZXh0IHN0ZXAuCmZ1bmN0aW9uIF91cGxvYWRGaWxlc0NvbnRpbnVlKG91dHB1dElkKSB7CiAgY29uc3Qgb3V0cHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG91dHB1dElkKTsKICBjb25zdCBzdGVwcyA9IG91dHB1dEVsZW1lbnQuc3RlcHM7CgogIGNvbnN0IG5leHQgPSBzdGVwcy5uZXh0KG91dHB1dEVsZW1lbnQubGFzdFByb21pc2VWYWx1ZSk7CiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShuZXh0LnZhbHVlLnByb21pc2UpLnRoZW4oKHZhbHVlKSA9PiB7CiAgICAvLyBDYWNoZSB0aGUgbGFzdCBwcm9taXNlIHZhbHVlIHRvIG1ha2UgaXQgYXZhaWxhYmxlIHRvIHRoZSBuZXh0CiAgICAvLyBzdGVwIG9mIHRoZSBnZW5lcmF0b3IuCiAgICBvdXRwdXRFbGVtZW50Lmxhc3RQcm9taXNlVmFsdWUgPSB2YWx1ZTsKICAgIHJldHVybiBuZXh0LnZhbHVlLnJlc3BvbnNlOwogIH0pOwp9CgovKioKICogR2VuZXJhdG9yIGZ1bmN0aW9uIHdoaWNoIGlzIGNhbGxlZCBiZXR3ZWVuIGVhY2ggYXN5bmMgc3RlcCBvZiB0aGUgdXBsb2FkCiAqIHByb2Nlc3MuCiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dElkIEVsZW1lbnQgSUQgb2YgdGhlIGlucHV0IGZpbGUgcGlja2VyIGVsZW1lbnQuCiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRwdXRJZCBFbGVtZW50IElEIG9mIHRoZSBvdXRwdXQgZGlzcGxheS4KICogQHJldHVybiB7IUl0ZXJhYmxlPCFPYmplY3Q+fSBJdGVyYWJsZSBvZiBuZXh0IHN0ZXBzLgogKi8KZnVuY3Rpb24qIHVwbG9hZEZpbGVzU3RlcChpbnB1dElkLCBvdXRwdXRJZCkgewogIGNvbnN0IGlucHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlucHV0SWQpOwogIGlucHV0RWxlbWVudC5kaXNhYmxlZCA9IGZhbHNlOwoKICBjb25zdCBvdXRwdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQob3V0cHV0SWQpOwogIG91dHB1dEVsZW1lbnQuaW5uZXJIVE1MID0gJyc7CgogIGNvbnN0IHBpY2tlZFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgaW5wdXRFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIChlKSA9PiB7CiAgICAgIHJlc29sdmUoZS50YXJnZXQuZmlsZXMpOwogICAgfSk7CiAgfSk7CgogIGNvbnN0IGNhbmNlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpOwogIGlucHV0RWxlbWVudC5wYXJlbnRFbGVtZW50LmFwcGVuZENoaWxkKGNhbmNlbCk7CiAgY2FuY2VsLnRleHRDb250ZW50ID0gJ0NhbmNlbCB1cGxvYWQnOwogIGNvbnN0IGNhbmNlbFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgY2FuY2VsLm9uY2xpY2sgPSAoKSA9PiB7CiAgICAgIHJlc29sdmUobnVsbCk7CiAgICB9OwogIH0pOwoKICAvLyBXYWl0IGZvciB0aGUgdXNlciB0byBwaWNrIHRoZSBmaWxlcy4KICBjb25zdCBmaWxlcyA9IHlpZWxkIHsKICAgIHByb21pc2U6IFByb21pc2UucmFjZShbcGlja2VkUHJvbWlzZSwgY2FuY2VsUHJvbWlzZV0pLAogICAgcmVzcG9uc2U6IHsKICAgICAgYWN0aW9uOiAnc3RhcnRpbmcnLAogICAgfQogIH07CgogIGNhbmNlbC5yZW1vdmUoKTsKCiAgLy8gRGlzYWJsZSB0aGUgaW5wdXQgZWxlbWVudCBzaW5jZSBmdXJ0aGVyIHBpY2tzIGFyZSBub3QgYWxsb3dlZC4KICBpbnB1dEVsZW1lbnQuZGlzYWJsZWQgPSB0cnVlOwoKICBpZiAoIWZpbGVzKSB7CiAgICByZXR1cm4gewogICAgICByZXNwb25zZTogewogICAgICAgIGFjdGlvbjogJ2NvbXBsZXRlJywKICAgICAgfQogICAgfTsKICB9CgogIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykgewogICAgY29uc3QgbGkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpOwogICAgbGkuYXBwZW5kKHNwYW4oZmlsZS5uYW1lLCB7Zm9udFdlaWdodDogJ2JvbGQnfSkpOwogICAgbGkuYXBwZW5kKHNwYW4oCiAgICAgICAgYCgke2ZpbGUudHlwZSB8fCAnbi9hJ30pIC0gJHtmaWxlLnNpemV9IGJ5dGVzLCBgICsKICAgICAgICBgbGFzdCBtb2RpZmllZDogJHsKICAgICAgICAgICAgZmlsZS5sYXN0TW9kaWZpZWREYXRlID8gZmlsZS5sYXN0TW9kaWZpZWREYXRlLnRvTG9jYWxlRGF0ZVN0cmluZygpIDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ24vYSd9IC0gYCkpOwogICAgY29uc3QgcGVyY2VudCA9IHNwYW4oJzAlIGRvbmUnKTsKICAgIGxpLmFwcGVuZENoaWxkKHBlcmNlbnQpOwoKICAgIG91dHB1dEVsZW1lbnQuYXBwZW5kQ2hpbGQobGkpOwoKICAgIGNvbnN0IGZpbGVEYXRhUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7CiAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7CiAgICAgIHJlYWRlci5vbmxvYWQgPSAoZSkgPT4gewogICAgICAgIHJlc29sdmUoZS50YXJnZXQucmVzdWx0KTsKICAgICAgfTsKICAgICAgcmVhZGVyLnJlYWRBc0FycmF5QnVmZmVyKGZpbGUpOwogICAgfSk7CiAgICAvLyBXYWl0IGZvciB0aGUgZGF0YSB0byBiZSByZWFkeS4KICAgIGxldCBmaWxlRGF0YSA9IHlpZWxkIHsKICAgICAgcHJvbWlzZTogZmlsZURhdGFQcm9taXNlLAogICAgICByZXNwb25zZTogewogICAgICAgIGFjdGlvbjogJ2NvbnRpbnVlJywKICAgICAgfQogICAgfTsKCiAgICAvLyBVc2UgYSBjaHVua2VkIHNlbmRpbmcgdG8gYXZvaWQgbWVzc2FnZSBzaXplIGxpbWl0cy4gU2VlIGIvNjIxMTU2NjAuCiAgICBsZXQgcG9zaXRpb24gPSAwOwogICAgd2hpbGUgKHBvc2l0aW9uIDwgZmlsZURhdGEuYnl0ZUxlbmd0aCkgewogICAgICBjb25zdCBsZW5ndGggPSBNYXRoLm1pbihmaWxlRGF0YS5ieXRlTGVuZ3RoIC0gcG9zaXRpb24sIE1BWF9QQVlMT0FEX1NJWkUpOwogICAgICBjb25zdCBjaHVuayA9IG5ldyBVaW50OEFycmF5KGZpbGVEYXRhLCBwb3NpdGlvbiwgbGVuZ3RoKTsKICAgICAgcG9zaXRpb24gKz0gbGVuZ3RoOwoKICAgICAgY29uc3QgYmFzZTY0ID0gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIGNodW5rKSk7CiAgICAgIHlpZWxkIHsKICAgICAgICByZXNwb25zZTogewogICAgICAgICAgYWN0aW9uOiAnYXBwZW5kJywKICAgICAgICAgIGZpbGU6IGZpbGUubmFtZSwKICAgICAgICAgIGRhdGE6IGJhc2U2NCwKICAgICAgICB9LAogICAgICB9OwogICAgICBwZXJjZW50LnRleHRDb250ZW50ID0KICAgICAgICAgIGAke01hdGgucm91bmQoKHBvc2l0aW9uIC8gZmlsZURhdGEuYnl0ZUxlbmd0aCkgKiAxMDApfSUgZG9uZWA7CiAgICB9CiAgfQoKICAvLyBBbGwgZG9uZS4KICB5aWVsZCB7CiAgICByZXNwb25zZTogewogICAgICBhY3Rpb246ICdjb21wbGV0ZScsCiAgICB9CiAgfTsKfQoKc2NvcGUuZ29vZ2xlID0gc2NvcGUuZ29vZ2xlIHx8IHt9OwpzY29wZS5nb29nbGUuY29sYWIgPSBzY29wZS5nb29nbGUuY29sYWIgfHwge307CnNjb3BlLmdvb2dsZS5jb2xhYi5fZmlsZXMgPSB7CiAgX3VwbG9hZEZpbGVzLAogIF91cGxvYWRGaWxlc0NvbnRpbnVlLAp9Owp9KShzZWxmKTsK",
+       "headers": [
+        [
+         "content-type",
+         "application/javascript"
+        ]
+       ],
+       "ok": true,
+       "status": 200,
+       "status_text": ""
+      }
+     }
+    },
+    "id": "qvxTx9m9xZJ2",
+    "outputId": "5d709c16-ea27-4214-c75a-fe3c32d85de6"
+   },
+   "outputs": [
+    {
+     "ename": "ModuleNotFoundError",
+     "evalue": "No module named 'google.colab'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-21-9dc6fa463cb8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;31m# YOUR ACTION REQUIRED:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;31m# Upload any test file to the target system.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mgoogle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolab\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mfiles\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      5\u001b[0m \u001b[0muploaded\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfiles\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mfn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0muploaded\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'google.colab'"
+     ]
+    }
+   ],
+   "source": [
+    "# Snippet as provided in https://colab.research.google.com/notebooks/io.ipynb\n",
+    "# YOUR ACTION REQUIRED:\n",
+    "# Upload any test file to the target system.\n",
+    "from google.colab import files\n",
+    "uploaded = files.upload()\n",
+    "for fn in uploaded.keys():\n",
+    "  print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
+    "      name=fn, length=len(uploaded[fn])))\n",
+    "# The file should now appear in the current working directory.\n",
+    "!pwd\n",
+    "!ls -l"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 17
+    },
+    "id": "toQxJSVfxjew",
+    "outputId": "c97f24cd-a8fb-4dd9-85f6-507445f519c1"
+   },
+   "outputs": [],
+   "source": [
+    "# A file can also be downloaded by using:\n",
+    "from google.colab import files\n",
+    "!touch test_file.txt\n",
+    "files.download('test_file.txt')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "swVo-jxCW6KK"
+   },
+   "source": [
+    "**Connecting to Google Cloud Storage**\n",
+    "\n",
+    "[Google Cloud Storage](https://cloud.google.com/storage/?hl=de) (GCS) is a cloud file storage service with a RESTful API.\n",
+    "\n",
+    "We can utilize it to store our own data or to access data provided by the following identifier:\n",
+    "\n",
+    "\n",
+    "```\n",
+    "gs://[BUCKET_NAME]/[OBJECT_NAME]\n",
+    "```\n",
+    "\n",
+    "We'll use the data provided in **gs://amld-datasets/zoo_img** as can be seen below.\n",
+    "\n",
+    "Before we can interact with the cloud environment, we need to grant permissions accordingly (also see [External data: Cloud Storage](https://colab.research.google.com/notebooks/io.ipynb#scrollTo=S7c8WYyQdh5i))."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "id": "1aJ1e7JFVIsQ"
+   },
+   "outputs": [],
+   "source": [
+    "from google.colab import auth\n",
+    "auth.authenticate_user()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "f6_4yqiOfWKt"
+   },
+   "source": [
+    "List a subset of the contained files using the [gsutil tool](https://cloud.google.com/storage/docs/gsutil?hl=en)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 221
+    },
+    "id": "wJAutwkEWWxg",
+    "outputId": "d20afb18-b0b1-4dce-f6c4-bfcdf7363ab9"
+   },
+   "outputs": [],
+   "source": [
+    "!gsutil ls gs://amld-datasets/zoo_img | head"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "d10y2KZpfsed"
+   },
+   "source": [
+    "Conveniently, TensorFlow natively supports multiple file systems such as:\n",
+    "\n",
+    "*   GCS - Google Cloud Storage\n",
+    "*   HDFS - Hadoop\n",
+    "*   S3 - Amazon Simple Storage\n",
+    "\n",
+    "An example for the GCS filesystem can be seen below."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 187
+    },
+    "id": "MDUnLXGXWnO8",
+    "outputId": "dc694698-93d4-4132-ee3f-638eb1db5159"
+   },
+   "outputs": [],
+   "source": [
+    "# Note: This cell hangs if you forget to call auth.authenticate_user() above.\n",
+    "tf.io.gfile.glob('gs://amld-datasets/zoo_img/*')[:10]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "AHhyyTLRHDlH"
+   },
+   "source": [
+    "## Snippets\n",
+    "\n",
+    "Finally, we can take a look at the snippets support in Colab.\n",
+    "> If you're using Jupyter please see [Jupyter contrib nbextensions - Snippets menu](https://jupyter-contrib-nbextensions.readthedocs.io/en/latest/nbextensions/snippets_menu/readme.html) as this is not natively supported.\n",
+    "\n",
+    "Snippets are a way to quickly \"bookmark\" pieces of code or text that you might want to insert into specific cells.\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "id": "4Dph99hAr61H"
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR ACTION REQUIRED:\n",
+    "# Explore existing snippets by going to the `Code snippets` section.\n",
+    "# Click on the <> button on the left sidebar to open the snippets.\n",
+    "# Alternatively, you can press `<CTRL><ALT><P>` (or `<COMMAND><OPTION><P>` for OS X)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {
+    "id": "_rO9y-43U_lL"
+   },
+   "outputs": [
+    {
+     "ename": "ModuleNotFoundError",
+     "evalue": "No module named 'google.colab'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-22-f69ea5624b36>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mgoogle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolab\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msnippets\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;31m# snippets.register('https://colab.research.google.com/drive/1OFSjEmqC-UC66xs-LR7-xmgkvxYTrAcN')\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'google.colab'"
+     ]
+    }
+   ],
+   "source": [
+    "from google.colab import snippets\n",
+    "# snippets.register('https://colab.research.google.com/drive/1OFSjEmqC-UC66xs-LR7-xmgkvxYTrAcN')"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "57T5LlVEpfp2"
+   },
+   "source": [
+    "**Pro tip** : Maybe this is a good moment to create your own snippets and register them in settings. You can then start collecting often-used code and have it ready when you need it..."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "grr29b3-gCd-"
+   },
+   "source": [
+    "# ----- Optional part -----"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "W0Uq0G0LrtjG"
+   },
+   "source": [
+    "## Custom line magic\n",
+    "\n",
+    "You can also define your own line/cell magic in the following way."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "id": "Y8bjXSjBJ2oP"
+   },
+   "outputs": [],
+   "source": [
+    "from IPython.core.magic import register_line_cell_magic\n",
+    "\n",
+    "@register_line_cell_magic\n",
+    "def mymagic(line_content, cell_content=None):\n",
+    "  print('line_content=\"%s\" cell_content=\"%s\"' % (line_content, cell_content))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "lu7Z7VTEKPWh",
+    "outputId": "1b3a751e-384d-4e67-f8b8-30ced872e0b0"
+   },
+   "outputs": [],
+   "source": [
+    "%mymagic Howdy Alice!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 51
+    },
+    "id": "GGBRfLm6LTvU",
+    "outputId": "2d413b95-ce2f-4af4-c226-ac4792460afa"
+   },
+   "outputs": [],
+   "source": [
+    "%%mymagic simple question\n",
+    "Howdy Alice!\n",
+    "how are you?"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "hZUSUu5A1mAD"
+   },
+   "source": [
+    "## Forms\n",
+    "\n",
+    "You can simplify cells by hiding their code and displaying a form instead.\n",
+    "\n",
+    "\n",
+    "**Note:** You can display or hide the code by double clicking the form which might be on the right side."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "cellView": "form",
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "2EkpzaQA1u7y",
+    "outputId": "61d75dff-eb8e-40e2-dd11-28fb9cd9bca9"
+   },
+   "outputs": [],
+   "source": [
+    "#@title Execute me\n",
+    "\n",
+    "# Hidden cell content.\n",
+    "print(\"Double click the cell to see its content.\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "cellView": "both",
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 51
+    },
+    "id": "adKaHZNZ2jZo",
+    "outputId": "4eb20e86-c4a3-4521-96f5-e487717d6748"
+   },
+   "outputs": [],
+   "source": [
+    "# Form example mostly taken from \"Adding form fields\" Snippet.\n",
+    "#@title Example form\n",
+    "#@markdown Specify some test data and execute this cell.\n",
+    "\n",
+    "string_type = 'test_string' #@param {type: \"string\"}\n",
+    "slider_value = 145  #@param {type: \"slider\", min: 100, max: 200}\n",
+    "number = 1339  #@param {type: \"number\"}\n",
+    "date = '2019-01-26'  #@param {type: \"date\"}\n",
+    "pick_me = \"a\"  #@param ['a', 'b', 'c']\n",
+    "#@markdown ---\n",
+    "print(\"Submitted data:\")\n",
+    "print(string_type, slider_value, number, date, pick_me)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "kx_ETyD5r0vJ"
+   },
+   "source": [
+    "## Interactive debugging"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "8rXJALYPr-Eg"
+   },
+   "source": [
+    "An example of an IPython tool that you can utilize is the interactive debugger \n",
+    "provided inside an IPython environment like Colab.\n",
+    "\n",
+    "For instance, by using **%pdb on**, you can automatically trigger the debugger on exceptions to further analyze the state.\n",
+    "\n",
+    "Some useful debugger commands are:\n",
+    "\n",
+    "Description | Command\n",
+    "---|---\n",
+    "**h**(elp) | Display available commands\n",
+    "**p**(rint) `x` | Show content of object `x`\n",
+    "**w**(here) | Show current instruction pointer position\n",
+    "**q**(uit) | Leave the debugger"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "colab": {
+     "base_uri": "https://localhost:8080/",
+     "height": 34
+    },
+    "id": "sMGORnaE2yJ-",
+    "outputId": "65d027eb-2094-4a20-9f8d-1e8cb759add2"
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR ACTION REQUIRED:\n",
+    "# Execute this cell, print the variable contents of a, b and exit the debugger.\n",
+    "%pdb on\n",
+    "a = 67069 / 47 - 0x5a\n",
+    "b = a - 0x539\n",
+    "#c = a / b  # Will throw an exception."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "eHQDeKx06WPq"
+   },
+   "source": [
+    "We'll not dive further into debugging but it's useful to know that this option exists.\n",
+    "\n",
+    "Please see [Python Docs - pdb The Python Debugger](https://docs.python.org/2/library/pdb.html) for more information."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "id": "kPD8cAscKCes"
+   },
+   "source": [
+    "## A Word of Warning\n",
+    "\n",
+    "While notebook environments like Colab/Jupyter provide many benefits, they also come with some caveats that you should be aware of.\n",
+    "One example is that you might quickly execute cells in a wrong order leading to unexpected behavior.\n",
+    "\n",
+    "If you're interested in more examples feel free to take a look at:\n",
+    "\n",
+    "[Youtube - I don't like notebooks by Joel Grus](https://www.youtube.com/watch?v=7jiPeIFXb6U) (duration ~56 minutes)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "id": "svJa3PRtN4l3"
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "colab": {
+   "collapsed_sections": [],
+   "name": "Jupyter Notebook - Introduction Colab.ipynb",
+   "provenance": []
+  },
+  "kernelspec": {
+   "display_name": "Python 3",
+   "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.7.6"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
-- 
GitLab