{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_shock(a,i,k):\n",
    "    n = len(a)\n",
    "    if (i<k):\n",
    "        k = i\n",
    "    thresh = np.sort(a[(i-k):i+1])[::-1][int(k/10)]\n",
    "    return a[i]>thresh"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "window_size = 250\n",
    "def get_events(data):\n",
    "    n = len(data)\n",
    "    nodes = list(data.columns)\n",
    "    events = []\n",
    "    for x in nodes:\n",
    "        print(x)\n",
    "        event = [False for i in range(n)]\n",
    "        for i in range(n):\n",
    "            event[i] = is_shock(data[x],i,window_size)\n",
    "        tick = np.where(event)[0].tolist()\n",
    "        events.append(np.asarray(tick).astype(np.double))\n",
    "    return events"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "raw = pd.read_csv(\"data/ddly/ddly-data.csv\",delimiter=\";\")\n",
    "raw = raw.drop(['dd/mm/yy'],axis = 1)\n",
    "bonds = [\"hsba.ln\", \"X8306.to\", \"bnp.fr\", \"jpm\", \"dbk.xe\", \"barc.ln\", \"aca.fr\", \"bac\", \"c\", \"X8411.to\", \"gle.fr\", \"rbs.ln\", \"X8316.to\", \"san.mc\", \"wfc\", \"inga.ae\", \"lloy.ln\", \"ucg.mi\", \"ubsn.vx\", \"csgn.vx\", \"gs\", \"ndasek.sk\", \"isp.mi\", \"MS\", \"td.t\", \"ry.t\", \"bbva.mc\", \"cbk.xe\", \"nab.au\", \"bns.t\", \"cba.au\", \"stan.ln\", \"X600036.sh\", \"anz.au\", \"wbc.au\", \"X600000.sh\", \"danske.ko\", \"sber.mz\", \"X600016.sh\", \"bmo.t\", \"itub4.br\", \"X8308.to\", \"X8604.to\", \"X8309.to\", \"sbin.in\", \"dnb.os\", \"shba.sk\", \"seba.sk\", \"cm.t\", \"bk.us\", \"usb\", \"bbdc4.br\", \"kbc.bt\", \"pnc.us\", \"d05.sg\", \"X000001.sz\", \"X053000.se\", \"dexb.bt\", \"cof\", \"X055550.se\", \"sweda.sk\", \"X600015.sh\", \"ebs.vi\", \"bmps.mi\", \"stt.us\", \"sab.mc\", \"u11.sg\", \"pop.mc\", \"X024110.SE\", \"BBT\", \"bir.db\", \"NA.T\", \"STI.US\", \"bp.mi\", \"maybank.ku\", \"aib.db\", \"sbk.jo\", \"AXP\", \"ete.at\", \"mqg.au\", \"X8354.to\", \"X8332.to\", \"poh1s.he\", \"fitb.us\", \"rf.us\", \"X8331.to\", \"uni.mi\", \"bcp.lb\", \"cimb.ku\", \"bankbaroda.in\", \"isctr.is\", \"bes.lb\", \"X8377.to\", \"X8355.to\", \"mb.mi\", \"X8418.to\"]\n",
    "# bonds = [\"US_b\", \"UK_b\", \"GER_b\", \"FRA_b\", \"ITA_b\", \"ESP_b\", \"GRC_b\", \"JPN_b\", \"CAN_b\", \"AUS_b\"]\n",
    "raw = raw.filter(bonds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hsba.ln\n",
      "X8306.to\n",
      "bnp.fr\n",
      "jpm\n",
      "dbk.xe\n",
      "barc.ln\n",
      "aca.fr\n",
      "bac\n",
      "c\n",
      "X8411.to\n",
      "gle.fr\n",
      "rbs.ln\n",
      "X8316.to\n",
      "san.mc\n",
      "wfc\n",
      "inga.ae\n",
      "lloy.ln\n",
      "ucg.mi\n",
      "ubsn.vx\n",
      "csgn.vx\n",
      "gs\n",
      "ndasek.sk\n",
      "isp.mi\n",
      "MS\n",
      "td.t\n",
      "ry.t\n",
      "bbva.mc\n",
      "cbk.xe\n",
      "nab.au\n",
      "bns.t\n",
      "cba.au\n",
      "stan.ln\n",
      "X600036.sh\n",
      "anz.au\n",
      "wbc.au\n",
      "X600000.sh\n",
      "danske.ko\n",
      "sber.mz\n",
      "X600016.sh\n",
      "bmo.t\n",
      "itub4.br\n",
      "X8308.to\n",
      "X8604.to\n",
      "X8309.to\n",
      "sbin.in\n",
      "dnb.os\n",
      "shba.sk\n",
      "seba.sk\n",
      "cm.t\n",
      "bk.us\n",
      "usb\n",
      "bbdc4.br\n",
      "kbc.bt\n",
      "pnc.us\n",
      "d05.sg\n",
      "X000001.sz\n",
      "X053000.se\n",
      "dexb.bt\n",
      "cof\n",
      "X055550.se\n",
      "sweda.sk\n",
      "X600015.sh\n",
      "ebs.vi\n",
      "bmps.mi\n",
      "stt.us\n",
      "sab.mc\n",
      "u11.sg\n",
      "pop.mc\n",
      "X024110.SE\n",
      "BBT\n",
      "bir.db\n",
      "NA.T\n",
      "STI.US\n",
      "bp.mi\n",
      "maybank.ku\n",
      "aib.db\n",
      "sbk.jo\n",
      "AXP\n",
      "ete.at\n",
      "mqg.au\n",
      "X8354.to\n",
      "X8332.to\n",
      "poh1s.he\n",
      "fitb.us\n",
      "rf.us\n",
      "X8331.to\n",
      "uni.mi\n",
      "bcp.lb\n",
      "cimb.ku\n",
      "bankbaroda.in\n",
      "isctr.is\n",
      "bes.lb\n",
      "X8377.to\n",
      "X8355.to\n",
      "mb.mi\n",
      "X8418.to\n"
     ]
    }
   ],
   "source": [
    "nodes = list(raw.columns)\n",
    "p = len(nodes)\n",
    "T = len(raw)\n",
    "data = get_events(raw).copy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "df = pd.DataFrame(columns=['alarm_id','start_timestamp','device_id'])\n",
    "\n",
    "for i in range(len(data)):\n",
    "    for j in range(len(data[i])):\n",
    "        new_row = {'alarm_id': i, 'start_timestamp': data[i][j], 'device_id': 0}\n",
    "        new_df = pd.DataFrame(new_row, index=[0])\n",
    "        df = pd.concat([df, new_df])\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['start_timestamp'] = df['start_timestamp'] * 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.to_csv('ddly-data-shock.csv', index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7ff191b9c130>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 64864 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ddl_data = pd.read_csv(\"data/ddly/ddly-data.csv\",delimiter=\";\")\n",
    "\n",
    "range0=50\n",
    "range1=100\n",
    "\n",
    "l1 = \"CAN_b\"\n",
    "l2 = \"US_b\"\n",
    "\n",
    "plt.plot(ddl_data.index[range0:range1],ddl_data[l1][range0:range1], label=l1)   \n",
    "plt.plot(ddl_data.index[range0:range1],ddl_data[l2][range0:range1], label=l2)\n",
    "plt.legend()\n",
    "# plt.plot(ddl_data.index,ddl_data['CAN_b'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "names = dict(enumerate(nodes))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "graph = np.load(\"output_tracked/ddly.npy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 80), (2, 5), (2, 11), (2, 13), (2, 20), (2, 22), (2, 26), (2, 82), (4, 0), (4, 2), (4, 6), (4, 10), (4, 15), (4, 16), (4, 19), (4, 21), (4, 27), (4, 36), (4, 46), (4, 47), (4, 52), (4, 60), (4, 83), (8, 3), (8, 4), (8, 7), (8, 14), (8, 23), (8, 24), (8, 31), (8, 48), (8, 49), (8, 50), (8, 53), (8, 58), (8, 64), (8, 69), (8, 71), (8, 72), (8, 77), (9, 1), (9, 12), (9, 41), (9, 43), (14, 11), (15, 62), (19, 18), (23, 45), (24, 39), (34, 30), (39, 25), (39, 29), (49, 5), (50, 49), (50, 83), (69, 84), (71, 33), (71, 48), (74, 64), (93, 81), (93, 85)]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[('X8306.to', 'X8354.to'),\n",
       " ('bnp.fr', 'barc.ln'),\n",
       " ('bnp.fr', 'rbs.ln'),\n",
       " ('bnp.fr', 'san.mc'),\n",
       " ('bnp.fr', 'gs'),\n",
       " ('bnp.fr', 'isp.mi'),\n",
       " ('bnp.fr', 'bbva.mc'),\n",
       " ('bnp.fr', 'poh1s.he'),\n",
       " ('dbk.xe', 'hsba.ln'),\n",
       " ('dbk.xe', 'bnp.fr'),\n",
       " ('dbk.xe', 'aca.fr'),\n",
       " ('dbk.xe', 'gle.fr'),\n",
       " ('dbk.xe', 'inga.ae'),\n",
       " ('dbk.xe', 'lloy.ln'),\n",
       " ('dbk.xe', 'csgn.vx'),\n",
       " ('dbk.xe', 'ndasek.sk'),\n",
       " ('dbk.xe', 'cbk.xe'),\n",
       " ('dbk.xe', 'danske.ko'),\n",
       " ('dbk.xe', 'shba.sk'),\n",
       " ('dbk.xe', 'seba.sk'),\n",
       " ('dbk.xe', 'kbc.bt'),\n",
       " ('dbk.xe', 'sweda.sk'),\n",
       " ('dbk.xe', 'fitb.us'),\n",
       " ('c', 'jpm'),\n",
       " ('c', 'dbk.xe'),\n",
       " ('c', 'bac'),\n",
       " ('c', 'wfc'),\n",
       " ('c', 'MS'),\n",
       " ('c', 'td.t'),\n",
       " ('c', 'stan.ln'),\n",
       " ('c', 'cm.t'),\n",
       " ('c', 'bk.us'),\n",
       " ('c', 'usb'),\n",
       " ('c', 'pnc.us'),\n",
       " ('c', 'cof'),\n",
       " ('c', 'stt.us'),\n",
       " ('c', 'BBT'),\n",
       " ('c', 'NA.T'),\n",
       " ('c', 'STI.US'),\n",
       " ('c', 'AXP'),\n",
       " ('X8411.to', 'X8306.to'),\n",
       " ('X8411.to', 'X8316.to'),\n",
       " ('X8411.to', 'X8308.to'),\n",
       " ('X8411.to', 'X8309.to'),\n",
       " ('wfc', 'rbs.ln'),\n",
       " ('inga.ae', 'ebs.vi'),\n",
       " ('csgn.vx', 'ubsn.vx'),\n",
       " ('MS', 'dnb.os'),\n",
       " ('td.t', 'bmo.t'),\n",
       " ('wbc.au', 'cba.au'),\n",
       " ('bmo.t', 'ry.t'),\n",
       " ('bmo.t', 'bns.t'),\n",
       " ('bk.us', 'barc.ln'),\n",
       " ('usb', 'bk.us'),\n",
       " ('usb', 'fitb.us'),\n",
       " ('BBT', 'rf.us'),\n",
       " ('NA.T', 'anz.au'),\n",
       " ('NA.T', 'cm.t'),\n",
       " ('maybank.ku', 'stt.us'),\n",
       " ('X8355.to', 'X8332.to'),\n",
       " ('X8355.to', 'X8331.to')]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pairs = np.where(graph == 1)\n",
    "pair_list = list(zip(pairs[0], pairs[1]))\n",
    "print(pair_list)\n",
    "renamed_pair_list = [(names[pair[0]], names[pair[1]]) for pair in pair_list]\n",
    "renamed_pair_list\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "import networkx as nx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "G_undi  = nx.from_numpy_array(graph)\n",
    "G  = nx.from_numpy_array(graph, create_using=nx.DiGraph)\n",
    "# Relabel nodes in the graph\n",
    "# G = nx.relabel_nodes(G, names)\n",
    "\n",
    "# Print the updated graph\n",
    "print(G)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 122584 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "nx.draw_kamada_kawai(G, with_labels=True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "isolates = list(nx.isolates(G))\n",
    "G.remove_nodes_from(isolates)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "cc = nx.connected_components(G_undi)\n",
    "unconnected_graphs = [G.subgraph(nodes) for nodes in cc]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 171836 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 42364 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 20464 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 16256 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "for g in unconnected_graphs:\n",
    "    if len(g.nodes()) > 1:\n",
    "        g = nx.relabel_nodes(g, names)\n",
    "        nx.draw_spring(g, with_labels=True)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                               Bank       Country   Mcap  Asset     Code  \\\n",
      "0                     HSBC Holdings            UK  201.0  2,671  hsba.gb   \n",
      "1    Mitsubishi UFJ Financial Group         Japan   82.2  2,504  mtbh.jp   \n",
      "2                       BNP Paribas        France  100.0  2,482   bnp.fr   \n",
      "3               JPMorgan Chase & Co            US  218.0  2,416   jpm.us   \n",
      "4                     Deutsche Bank       Germany   49.8  2,224   dbk.de   \n",
      "..                              ...           ...    ...    ...      ...   \n",
      "138          Malayan Banking Berhad      Malaysia   26.3    171   may.my   \n",
      "139              Allied Irish Banks       Ireland   99.9    162   aib.ie   \n",
      "140             Standard Bank Group  South Africa   17.7    161   sbk.za   \n",
      "141                American Express            US   94.7    153      axp   \n",
      "142         National Bank of Greece        Greece   12.1    153   ete.gr   \n",
      "\n",
      "         Ticker Continent  \n",
      "0       hsba.ln    Europe  \n",
      "1      X8306.to      Asia  \n",
      "2        bnp.fr    Europe  \n",
      "3           jpm   America  \n",
      "4        dbk.xe    Europe  \n",
      "..          ...       ...  \n",
      "138  maybank.ku      Asia  \n",
      "139      aib.db    Europe  \n",
      "140      sbk.jo    Africa  \n",
      "141         axp   America  \n",
      "142      ete.at    Europe  \n",
      "\n",
      "[143 rows x 7 columns]\n"
     ]
    }
   ],
   "source": [
    "metadata = pd.read_csv(\"data/ddly/tabula-DDLY-Data-Appendix.csv\",delimiter=\",\")\n",
    "countries = metadata['Country']\n",
    "# country to continent\n",
    "mapper = {\n",
    "    'UK': 'Europe',\n",
    "    'Japan': 'Asia',\n",
    "    'France': 'Europe',\n",
    "    'US': 'America',\n",
    "    'Germany': 'Europe',\n",
    "    'Spain': 'Europe',\n",
    "    'Netherland': 'Europe',\n",
    "    'Italy': 'Europe',\n",
    "    'Switzerland': 'Europe',\n",
    "    'Sweden': 'Europe',\n",
    "    'Canada': 'America',\n",
    "    'Australia': 'Australia',\n",
    "    'China': 'Asia',\n",
    "    'Denmark': 'Europe',\n",
    "    'Russia': 'Europe',\n",
    "    'Brazil': 'America',\n",
    "    'India': 'Asia',\n",
    "    'Norway': 'Europe',\n",
    "    'Belgium': 'Europe',\n",
    "    'Singapore': 'Asia',\n",
    "    'Korea': 'Asia',\n",
    "    'Austria': 'Europe',\n",
    "    'Ireland': 'Europe',\n",
    "    'Malaysia': 'Asia',\n",
    "    'South Africa': 'Africa',\n",
    "    'Greece': 'Europe',\n",
    "    'Finland': 'Europe',\n",
    "    'Portugal': 'Europe',\n",
    "    'Turkey': 'Europe'\n",
    "}\n",
    "continent = countries.map(mapper)\n",
    "metadata['Continent'] = continent\n",
    "\n",
    "print(metadata)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LR\n",
      "LR\n",
      "LR\n",
      "LR\n"
     ]
    }
   ],
   "source": [
    "import pygraphviz as pgv\n",
    "\n",
    "id_to_bank = dict(zip(metadata.index, metadata['Bank']))\n",
    "ind = 0\n",
    "for g in unconnected_graphs:\n",
    "    if len(g.nodes()) > 1:\n",
    "        g = nx.relabel_nodes(g, id_to_bank)\n",
    "        # color based on continent\n",
    "        continent_to_color = {\n",
    "            'Europe': 'lightblue',\n",
    "            'Asia': 'pink',\n",
    "            'America': 'lightgreen',\n",
    "            'Australia': 'yellow',\n",
    "        }\n",
    "        color_map = []\n",
    "        for node in g:\n",
    "            if node in metadata['Bank'].values:\n",
    "                color_map.append(continent_to_color[metadata[metadata['Bank'] == node]['Continent'].values[0]])\n",
    "            else:\n",
    "                color_map.append('black')\n",
    "        # assign size based on mcap\n",
    "        size_map = []\n",
    "        for node in g:\n",
    "            if node in metadata['Bank'].values:\n",
    "                size_map.append(metadata[metadata['Bank'] == node]['Mcap'].values[0])\n",
    "            else:\n",
    "                size_map.append(100)\n",
    "        \n",
    "        # # convert to graphviz\n",
    "\n",
    "        g = nx.nx_agraph.to_agraph(g)\n",
    "        # add color and size\n",
    "        for i, node in enumerate(g.nodes()):\n",
    "            node.attr['color'] = color_map[i]\n",
    "            node.attr['style'] = 'filled'\n",
    "            node.attr['shape'] = 'oval'\n",
    "            node.attr['width'] = size_map[i]/ 100 * 1.2\n",
    "            node.attr['height'] = size_map[i] / 100 * 1.2\n",
    "            node.attr[\"margin\"] = 0.1\n",
    "        # set fixed size\n",
    "        g.graph_attr['fixedsize'] = \"true\"\n",
    "        g.graph_attr['fontsize'] = \"20pt\"\n",
    "        g.graph_attr['rankdir'] = \"LR\"\n",
    "        g.graph_attr[\"size\"] = '90,30!'\n",
    "        print(g.graph_attr[\"rankdir\"])\n",
    "        \n",
    "        # set node labels with newline after 10 characters\n",
    "        for i, node in enumerate(g.nodes()):\n",
    "            name = str(node)\n",
    "            counter = 10\n",
    "            if len(name) > counter:\n",
    "                # split by words\n",
    "                words = name.split(' ')\n",
    "                name = ''\n",
    "                for word in words:\n",
    "                    if len(name) + len(word) > counter:\n",
    "                        name += '\\n' + word\n",
    "                        counter += 10\n",
    "                    else:\n",
    "                        name += \" \" + word\n",
    "            node.attr['label'] = name\n",
    "        g.write(f'graph{ind:d}.dot')\n",
    "        g.draw(f'graph{ind:d}.svg', format='svg', prog='twopi', args='-Goverlap=false -Gsplines=true -Gnodesep=3 -Gstart=5')\n",
    "        # # add legend\n",
    "        ind += 1\n",
    "        # # load image\n",
    "        # img = plt.imread(f'graph{ind-1:d}.png')\n",
    "        # plt.figure(figsize=(30,10),dpi=500)\n",
    "        # plt.imshow(img,interpolation=\"none\")\n",
    "        # plt.axis('off')\n",
    "        # import matplotlib.patches as mpatches\n",
    "        # handles = [mpatches.Patch(color=color, label=continent) for continent, color in continent_to_color.items()]\n",
    "        # plt.legend(handles=handles)\n",
    "        # plt.savefig(f'graph{ind-1:d}_legend.png', bbox_inches='tight',dpi=500)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "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.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
