{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "import os\n",
    "import argparse\n",
    "import json\n",
    "import cv2\n",
    "import sys\n",
    "sys.path += [os.path.abspath('../keras-yolo3-master')]\n",
    "sys.path += [os.path.abspath('../')]\n",
    "from utils.utils import get_yolo_boxes, makedirs\n",
    "from utils.bbox import draw_boxes\n",
    "from tensorflow.keras.models import load_model\n",
    "from tqdm import tqdm\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from panel_disconnect import disconnect\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Define Image Path and output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "input_path   = '../../Data/Ocoa/001/' \n",
    "output_path  = '../../Data/Ocoa/001_detect/'\n",
    "makedirs(output_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Load Model (Panel Detector, Soiling, Diode, Cell Damage)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.\n",
      "WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.\n",
      "WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.\n",
      "WARNING:tensorflow:No training configuration found in save file: the model was *not* compiled. Compile it manually.\n"
     ]
    }
   ],
   "source": [
    "## Config of trained model, change this for use different trained model\n",
    "config_path_panel  = 'config_full_yolo_panel_infer.json' #Panel\n",
    "config_path_soiling  = 'config_full_yolo_fault_1_infer.json' #Soiling\n",
    "config_path_diode  = 'config_full_yolo_fault_4_infer.json'  #Diode\n",
    "config_path_cellD  = 'config_full_yolo_fault_2_infer.json'  #Cell Damage\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "## Parameters of detection\n",
    "net_h, net_w = 416, 416 # a multiple of 32, the smaller the faster\n",
    "obj_thresh, nms_thresh, nms_thresh_panel = 0.5, 0.45, 0.3\n",
    "\n",
    "####################################################\n",
    "#####   Load the model Panel Detector  #############\n",
    "####################################################\n",
    "with open(config_path_panel) as config_buffer:\n",
    "        config_panel = json.load(config_buffer)\n",
    "\n",
    "os.environ['CUDA_VISIBLE_DEVICES'] = config_panel['train']['gpus']\n",
    "infer_model_panel = load_model(config_panel['train']['saved_weights_name'])\n",
    "\n",
    "####################################################\n",
    "#####   Load the model Soiling  #############\n",
    "####################################################\n",
    "with open(config_path_soiling) as config_buffer:\n",
    "        config_soiling = json.load(config_buffer)\n",
    "\n",
    "infer_model_soiling = load_model(config_soiling['train']['saved_weights_name'])\n",
    "\n",
    "####################################################\n",
    "#####   Load the model Diode  #############\n",
    "####################################################\n",
    "with open(config_path_diode) as config_buffer:\n",
    "        config_diode = json.load(config_buffer)\n",
    "\n",
    "infer_model_diode = load_model(config_diode['train']['saved_weights_name'])\n",
    "\n",
    "####################################################\n",
    "#####   Load the model Cell Damage  #############\n",
    "####################################################\n",
    "with open(config_path_cellD) as config_buffer:\n",
    "        config_cellD = json.load(config_buffer)\n",
    "\n",
    "infer_model_cellD = load_model(config_cellD['train']['saved_weights_name'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Load Image paths"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "image_paths = []\n",
    "\n",
    "if os.path.isdir(input_path):\n",
    "    for inp_file in os.listdir(input_path):\n",
    "        image_paths += [input_path + inp_file]\n",
    "else:\n",
    "    image_paths += [input_path]\n",
    "\n",
    "image_paths = [inp_file for inp_file in image_paths if (inp_file[-4:] in ['.jpg', '.png', 'JPEG'])]\n",
    "\n",
    "# the main loop\n",
    "times = []\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Detection of images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "../../Data/Ocoa/001/DJI_0027.jpg\n",
      "Elapsed time = 5.246682167053223\n",
      "../../Data/Ocoa/001/DJI_0147.jpg\n",
      "Elapsed time = 5.895338535308838\n",
      "../../Data/Ocoa/001/DJI_0166.jpg\n",
      "Elapsed time = 5.632398366928101\n",
      "../../Data/Ocoa/001/DJI_0100.jpg\n",
      "Elapsed time = 5.191319942474365\n",
      "../../Data/Ocoa/001/DJI_0014.jpg\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-52ef73f77509>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      7\u001b[0m     \u001b[0mboxes_diode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_yolo_boxes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minfer_model_diode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mimage\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_h\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_w\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfig_diode\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'model'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'anchors'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj_thresh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnms_thresh\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0mboxes_cellD\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_yolo_boxes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minfer_model_cellD\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mimage\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_h\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_w\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfig_cellD\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'model'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'anchors'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj_thresh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnms_thresh\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m     \u001b[0mboxes_panel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_yolo_boxes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minfer_model_panel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mimage\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_h\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_w\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfig_panel\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'model'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'anchors'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj_thresh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnms_thresh_panel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     10\u001b[0m     \u001b[0mboxes_panel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mbox\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mbox\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mboxes_panel\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mbox\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_score\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0mobj_thresh\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mboxes_disc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdisconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mimage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mboxes_panel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mz_thresh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1.8\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/Desktop/Rentadrone.cl-ai-test&SomeCode/model-definition/keras-yolo3-master/utils/utils.py\u001b[0m in \u001b[0;36mget_yolo_boxes\u001b[0;34m(model, images, net_h, net_w, anchors, obj_thresh, nms_thresh)\u001b[0m\n\u001b[1;32m    264\u001b[0m         \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0myolos\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[1;32m    265\u001b[0m             \u001b[0myolo_anchors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0manchors\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# config['model']['anchors']\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 266\u001b[0;31m             \u001b[0mboxes\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mdecode_netout\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0myolos\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0myolo_anchors\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj_thresh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_h\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnet_w\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    267\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    268\u001b[0m         \u001b[0;31m# correct the sizes of the bounding boxes\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/Desktop/Rentadrone.cl-ai-test&SomeCode/model-definition/keras-yolo3-master/utils/utils.py\u001b[0m in \u001b[0;36mdecode_netout\u001b[0;34m(netout_old, anchors, obj_thresh, net_h, net_w)\u001b[0m\n\u001b[1;32m    201\u001b[0m             \u001b[0mobjectness\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnetout\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mrow\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcol\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    202\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 203\u001b[0;31m             \u001b[0;32mif\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobjectness\u001b[0m \u001b[0;34m<=\u001b[0m \u001b[0mobj_thresh\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    204\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    205\u001b[0m             \u001b[0;31m# first 4 elements are x, y, w, and h\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/envs/new/lib/python3.7/site-packages/tensorflow_core/python/ops/gen_math_ops.py\u001b[0m in \u001b[0;36mless_equal\u001b[0;34m(x, y, name)\u001b[0m\n\u001b[1;32m   4979\u001b[0m       _result = _pywrap_tensorflow.TFE_Py_FastPathExecute(\n\u001b[1;32m   4980\u001b[0m         \u001b[0m_ctx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_context_handle\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtld\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdevice_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"LessEqual\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 4981\u001b[0;31m         tld.op_callbacks, x, y)\n\u001b[0m\u001b[1;32m   4982\u001b[0m       \u001b[0;32mreturn\u001b[0m \u001b[0m_result\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   4983\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0m_core\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_FallbackException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "for image_path in image_paths:\n",
    "    image = cv2.imread(image_path)\n",
    "    print(image_path)\n",
    "    start = time.time()\n",
    "    # predict the bounding boxes\n",
    "    boxes_soiling = get_yolo_boxes(infer_model_soiling, [image], net_h, net_w, config_soiling['model']['anchors'], obj_thresh, nms_thresh)[0]\n",
    "    boxes_diode = get_yolo_boxes(infer_model_diode, [image], net_h, net_w, config_diode['model']['anchors'], obj_thresh, nms_thresh)[0]\n",
    "    boxes_cellD = get_yolo_boxes(infer_model_cellD, [image], net_h, net_w, config_cellD['model']['anchors'], obj_thresh, nms_thresh)[0]\n",
    "    #boxes_panel = get_yolo_boxes(infer_model_panel, [image], net_h, net_w, config_panel['model']['anchors'], obj_thresh, nms_thresh_panel)[0]\n",
    "    #boxes_panel = [box for box in boxes_panel if box.get_score() > obj_thresh]\n",
    "    #boxes_disc = disconnect(image, boxes_panel, z_thresh = 1.8)\n",
    "    print('Elapsed time = {}'.format(time.time() - start))\n",
    "    times.append(time.time() - start)\n",
    "    # Draw boxes\n",
    "    draw_boxes(image, boxes_soiling, config_soiling['model']['labels'], obj_thresh, number_color = 0)\n",
    "    draw_boxes(image, boxes_diode, config_diode['model']['labels'], obj_thresh, number_color = 2)\n",
    "    draw_boxes(image, boxes_cellD, config_cellD['model']['labels'], obj_thresh, number_color = 4)\n",
    "    #draw_boxes(image, boxes_disc, ['disc'], obj_thresh, number_color = 5)\n",
    "    \n",
    "    cv2.imwrite(output_path + image_path.split('/')[-1], np.uint8(image))\n",
    "    # write the image with bounding boxes to file\n",
    "    #plt.figure(figsize=(16, 16))\n",
    "    #plt.imshow(image)\n",
    "\n",
    "file = open(output_path + 'time.txt','w')\n",
    "file.write('Tiempo promedio:' + str(np.mean(times)))\n",
    "file.close()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Example One image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "../../Data/Ocoa/001/DJI_0111.jpg\n",
      "Elapsed time = 5.186281204223633\n",
      "Elapsed time = 5.186866521835327\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f674b4ff610>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 333172 characters]\n",
      "text/plain": [
       "<Figure size 864x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 334000 characters]\n",
      "text/plain": [
       "<Figure size 864x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "image_path = image_paths[60]\n",
    "\n",
    "image = cv2.imread(image_path)\n",
    "plt.figure(figsize=(12, 10))\n",
    "plt.imshow(image)\n",
    "print(image_path)\n",
    "\n",
    "start = time.time()\n",
    "# predict the bounding boxes\n",
    "boxes_soiling = get_yolo_boxes(infer_model_soiling, [image], net_h, net_w, config_soiling['model']['anchors'], obj_thresh, nms_thresh)[0]\n",
    "boxes_diode = get_yolo_boxes(infer_model_diode, [image], net_h, net_w, config_diode['model']['anchors'], obj_thresh, nms_thresh)[0]\n",
    "boxes_cellD = get_yolo_boxes(infer_model_cellD, [image], net_h, net_w, config_cellD['model']['anchors'], obj_thresh, nms_thresh)[0]\n",
    "boxes_panel = get_yolo_boxes(infer_model_panel, [image], net_h, net_w, config_panel['model']['anchors'], obj_thresh, nms_thresh_panel)[0]\n",
    "boxes_panel = [box for box in boxes_panel if box.get_score() > obj_thresh]\n",
    "boxes_disc = disconnect(image, boxes_panel, z_thresh = 1.8)\n",
    "print('Elapsed time = {}'.format(time.time() - start))\n",
    "times.append(time.time() - start)\n",
    "# Draw boxes\n",
    "draw_boxes(image, boxes_soiling, config_soiling['model']['labels'], obj_thresh, number_color = 0)\n",
    "draw_boxes(image, boxes_diode, config_diode['model']['labels'], obj_thresh, number_color = 2)\n",
    "draw_boxes(image, boxes_cellD, config_cellD['model']['labels'], obj_thresh, number_color = 4)\n",
    "draw_boxes(image, boxes_disc, ['disc'], obj_thresh, number_color = 5)\n",
    "\n",
    "print('Elapsed time = {}'.format(time.time() - start))\n",
    "times.append(time.time() - start)\n",
    "plt.figure(figsize=(12, 10))\n",
    "plt.imshow(image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Type Fault\n",
    "## 1: Soiling Fault\n",
    "## 2: Affected Cell \n",
    "## 4: Diode Fault\n",
    "## disc: Panel Disconnected"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
