new version
authorLucas <laimaretto@gmail.com>
Wed, 1 Jul 2020 23:09:20 +0000 (20:09 -0300)
committerLucas <laimaretto@gmail.com>
Wed, 1 Jul 2020 23:09:20 +0000 (20:09 -0300)
python-graph-topology/README.md [new file with mode: 0644]
python-graph-topology/css/gstyle.css [new file with mode: 0755]
python-graph-topology/draw_topo_24_estable.py [deleted file]
python-graph-topology/draw_topo_26_estable.py [new file with mode: 0755]
python-graph-topology/flujo.graphml [new file with mode: 0644]
python-graph-topology/functions.py [new file with mode: 0644]
python-graph-topology/graph.php
python-graph-topology/js/jquery-image.js [new file with mode: 0755]
python-graph-topology/readme [deleted file]
python-graph-topology/sql_definitions.py [new file with mode: 0644]

diff --git a/python-graph-topology/README.md b/python-graph-topology/README.md
new file mode 100644 (file)
index 0000000..9e50b11
--- /dev/null
@@ -0,0 +1,60 @@
+# README #
+
+## Configuration of graphTopo plugin ##
+
+Follow these steps:
+
+#### System libraries
+
+```bash
+sudo apt install graphviz 
+sudo apt install python-mysqldb
+
+sudo pip install pandas
+sudo pip install graphviz
+sudo pip install networkx
+sudo pip install pydot
+sudo pip install pyyed
+sudo pip install matplotlib
+sudo pip install nuitka
+```
+
+#### Compile the python code
+
+```python
+python -m nuitka draw_topo_26_estable.py --nofollow-import-to=MySQLdb --nofollow-import-to=graphviz --nofollow-import-to=pydot --nofollow-import-to=time --nofollow-import-to=sys --nofollow-import-to=functools --nofollow-import-to=datetime --nofollow-import-to=pandas --nofollow-import-to=networkx --nofollow-import-to=operator --nofollow-import-to=itertools --nofollow-import-to=re --nofollow-import-to=matplotlib --follow-imports
+```
+
+#### Copy Files
+This includes the binary generated in the second step
+
+```bash
+sudo cp graph.php /var/www/racktables/plugins/
+sudo cp draw_topo_26_estable.bin /var/www/racktables/plugins/
+
+sudo cp logo.png /var/www/racktables/wwwroot/pix/
+sudo cp not.gif /var/www/racktables/wwwroot/pix/
+
+sudo cp js/ /var/www/racktables/plugins/ -r
+sudo cp css/ /var/www/racktables/plugins/ -r
+```
+
+#### Set permissiones
+This is needed for topologies storage
+```bash
+cd /var/www/racktables/wwwroot/
+sudo chown www-data:www-data pix/ -R
+```
+
+#### SQL ReadOnly User
+
+```mysql
+create user 'viewRT'@'%' identified by 'viewRT';
+grant select,lock tables,show view on racktables.* to 'viewRT'@'%';
+```
+
+## TODO
+
+1. Migrate the python-core to Python3.x
+2. Implement the new RackTables plugin-architecture in the file `graph.php`.
+3. Get rid of `graphviz` and try to manage all the topologies natively through `networkx`. This will make the code a lot cleaner.
\ No newline at end of file
diff --git a/python-graph-topology/css/gstyle.css b/python-graph-topology/css/gstyle.css
new file mode 100755 (executable)
index 0000000..d65fc03
--- /dev/null
@@ -0,0 +1,81 @@
+.help {
+       position: fixed;
+       right: 0;
+       z-index: 1000;
+}
+
+#help-button {
+       display: inline-block;
+       float:left;
+       margin-top: 10em;
+       padding-left:0.5em;
+       padding-right: 0.5em;
+       background-color: rgba(60, 120, 181, 0.5);
+       color: white;
+       cursor: pointer;
+}
+
+#help-pane {
+       display: inline-block;
+       overflow: auto;
+       background-color: rgba(60, 120, 181, 0.5);
+}
+
+#help-img {
+       display: block;
+       height: 80vh;
+}
+
+#help-msg {
+       margin: 0.25em 0;
+}
+
+.settings {
+       width: 98%;
+       padding-top:10px;
+       margin: auto;
+       overflow: hidden;
+}
+
+.parameters {
+       float:left;
+       clear:both;
+}
+
+.info {
+       float:right;
+       border: 1px dashed;
+       padding: 5px;
+}
+
+.result {
+       /*border: 1px solid;*/
+       width: 98%;
+       height: 98%;
+       margin: auto;
+}
+
+.topo {
+       /*border: 1px solid;*/
+       max-width: 100%;
+       margin: auto;
+       display: block;
+}
+
+.fields {
+       display: inline-block;
+       padding: 1em;
+}
+
+.gdiv {
+       display: inline-block;
+       padding-right: 1em;
+}
+
+.ginput {
+       display: block;
+}
+
+.not {
+       margin: auto;
+}
diff --git a/python-graph-topology/draw_topo_24_estable.py b/python-graph-topology/draw_topo_24_estable.py
deleted file mode 100644 (file)
index e11f8a8..0000000
+++ /dev/null
@@ -1,1112 +0,0 @@
-# coding=utf-8
-##########################################################
-# Name: draw_topo_02.py
-# Version: 0.2
-# Author: Lucas Aimaretto
-# mail: laimaretto@gmail.com
-# Date: 14-jun-2015
-#
-# - 0.1:       first draft
-#                      This version will graph any topology based on the tags of the routers.
-# - 0.2:       Reorder of functions; cleaning of code.
-# - 0.3:       Implementing of IP/PORT/Speed information. Change on function
-#                      fnc_build_query_connections SQL's query
-# - 0.4:       Included sync-e reference to each port. If not abailable, then N/A is shown.
-#                      For this, a sync_dict is created.
-# - 0.5:       Including system IP, sync order, color for not integrated routers.
-# - 0.6:       If no SFP, no speed can be obtained. Then "No SFP" is shown. If CES, ATM or ASAP, then "No ETH" is shown.
-# - 0.7:       fnc_build_query_objetos(.) modify to further filter out objects with tags (and no ipvnet)
-#                      fnc_build_query_interfaces(.) to bring IPs and interfaces
-#                      fnc_build_query_connections(.) now only brings connections and no IPs
-#                      fnc_cross_conn_inter(.) finds out IP for connections
-# - 0.8:       Asked whether to graph LAGs or not
-#                      TBD: consider when link label is something else than "LAG", "Hairpin" or "".
-# - 1.1:       Distinction between High, Mid and Low Ran
-# - 1.2:       Reducing font size of link's labels
-# - 1.3:       Including FO and ARSAT as possible labels for links
-# - 1.7:       Different colors for MR and HR
-# - 1.8:       Includes transmission with a list
-# - 1.9:       Ring topology now available
-# - 2.0:       Change Name of file to match Claro's format.
-# - 2.1:       Bug regarding getting the system IP of router: fnc_build_query_attributes(.)
-#                      TxType now considered when MIX TX is needed (ie: DWDM+MW)
-# - 2.2:       Option to graph nodes with the names, only.
-# - 2.3:       implementing argv to pass parameters in line
-#                      change \n to &#92;n in port an router when mode 1,2,3
-# - 2.4:       full custimoization via argv[]
-#                      Different color depending con Ref_Order
-
-#!/usr/bin/python
-import MySQLdb
-import graphviz as gv
-import time
-import sys
-import functools
-import datetime
-from operator import itemgetter
-from itertools import groupby
-
-########################################################################
-# Globals
-########################################################################
-
-ipran_tx = ["LAG_Y","HAIRPIN_Y","SDH","RADIO","DWDM","CDWM","FO",""]
-version_script="21"
-
-########################################################################
-# Functions
-########################################################################
-
-# Function to try if string is number
-def fnc_isNumber(text):
-
-       try:
-               int(text)
-               return 1
-       except:
-               return 0
-
-# Function to distinguish chains from rings
-def fnc_chains_ring(vector):
-       topoString=""
-       tempList=[]
-       len_vector= len(vector)
-       i=1
-
-       # We can have many topos inside vector
-       for topo in vector:
-
-               topoString = topo
-               charCount = topoString.count("_")
-               nameList=topoString.split("_")
-
-               #print nameList, charCount
-
-               if fnc_isNumber(nameList[0]==0):
-
-                       if charCount == 1:
-                               name1 = nameList[0]
-                               testNumber1 = nameList[1]
-
-                               # SF903_002
-                               if fnc_isNumber(testNumber1)==1:
-                                       tempList.append(("Anillo",name1,name1+"_"+testNumber1))
-                               else:
-                                       print "Wrong ring number: " + testNumber1 + " .Quitting..."
-                                       sys.exit(-1)
-
-                       elif charCount == 2:
-                               name1 = nameList[0]
-                               name2 = nameList[0] + "_" + nameList[1]
-                               testNumber1 = nameList[1]
-                               testNumber2 = nameList[2]
-
-                               # SF903_002_ARSAT
-                               if fnc_isNumber(testNumber1):
-                                       tempList.append(("Anillo_TX",name1,name1+"_"+testNumber1))
-                               # CF164_CFR17_001 or c1744_c3983_radial
-                               elif fnc_isNumber(testNumber2) or testNumber2=="RADIAL":
-                                       tempList.append(("Cadena",name2,name2+"_"+testNumber2))
-                               else:
-                                       print "Wrong chain name. Verify either: " + testNumber1 + " or " + testNumber2 + " .Quitting..."
-                                       sys.exit(-1)
-
-                       elif charCount == 3:
-                               name1 = nameList[0] + "_" + nameList[1]
-                               testNumber1 = nameList[2]
-
-                               # CF164_CFR17_001_MW
-                               if fnc_isNumber(testNumber1)==1:
-                                       tempList.append(("Cadena_TX",name1,name1+"_"+testNumber1))
-                               else:
-                                       print "Wrong chain_tx number: " + testNumber1 + " .Quitting..."
-                                       sys.exit(-1)
-
-                       elif charCount == 0:
-                               name1 = vector[0]
-                               tempList.append(("Other",name1,name1))
-
-                       else:
-                               print "Wrong topo name. Quitting..."
-                               sys.exit(-1)
-
-       return tempList
-
-# Function that builds the filename
-def fnc_build_filename(vector):
-       info = fnc_chains_ring(vector)
-       len_vector= len(vector)
-
-       if len_vector==1:
-
-               tipoTopo = info[0][0]
-               agregador = info[0][1]
-               topologia = info[0][2]
-
-               topoName1 = "Topology "
-               topoName2 = tipoTopo
-               topoName3 = " - MR LR - "
-               topoName4 = topologia
-               filename = "pix/topo/" + agregador + "/" + topoName1 + topoName2 + topoName3 + topoName4
-
-       elif len_vector >1:
-
-               tipoTopo = "-".join(list(set([name[0] for name in info])))
-               agregador = "-".join(list(set([name[1] for name in info])))
-               topologia = "-".join(list(set([name[2] for name in info])))
-
-               topoName1 = "Topology "
-               topoName2 = tipoTopo
-               topoName3 = " - MR LR - "
-               topoName4 = topologia
-               filename = "pix/topo/" + agregador + "/" + topoName1 + topoName2 + topoName3 + topoName4
-
-       now = datetime.datetime.now()
-       #filename=filename + "_" + version_script + "_" +now.strftime("%Y-%m-%d")+".dot"
-       return filename
-
-# Function that builds the SQL query to obtain the object Id based
-# on topo_name
-def fnc_build_query_objetos(vector):
-       query1=""
-       query2=""
-       len_vector = len(vector)
-       i=1
-
-       query1=(
-               "select "
-               "OBJ.name, "
-               "TS.entity_id "
-               "from "
-               "TagStorage as TS join Object as OBJ on (TS.entity_id=OBJ.id) "
-               "where entity_realm ='object' and "
-       )
-
-       for row in vector:
-               obj_id=str(row[0])
-               if i < len_vector:
-                       query2 = query2 + "tag_id = " + obj_id + " or "
-               else:
-                       query2 = query2 + "tag_id = " + obj_id
-               i=i+1
-
-       query = query1 + query2
-
-       return query
-
-# Function that builds the SQL query to obatin the topo_ID
-def fnc_build_query_topo_id(vector):
-       query1=""
-       query2=""
-       len_vector = len(vector)
-       i=1
-
-       query1=(
-               "select id from TagTree where "
-       )
-
-       for row in vector:
-               obj_id="'" + row + "'"
-               if i < len_vector:
-                       query2 = query2 + "tag = " + obj_id + " or "
-               else:
-                       query2 = query2 + "tag = " + obj_id
-               i=i+1
-
-       query = query1 + query2
-
-       return query
-
-# Function that removes ports from a router if such port connects
-# to a router that does not have a requested tag.
-def fnc_remove_routers_wotag(object_vector, connex_vector):
-
-       temp_list=[]
-       for o in object_vector:
-               temp_list.append(o[0])
-
-       final_list=[item for item in connex_vector if item[0] in temp_list and item[5] in temp_list]
-
-       return final_list
-
-
-# Function that obtains the attributes values per object ID
-# It also brings the system IP of the router.
-def fnc_build_query_attributes(vector):
-       query1=""
-       query2=""
-       query3=""
-       query4=""
-       len_vector = len(vector)
-
-       query1=(
-       "select "
-       "ob.name, "
-       "concat(ob.name,\"_\",av.string_value) as node, "
-       "a.name, "
-       "av.string_value, "
-       "d.dict_value "
-       "from Object as ob "
-       "join AttributeValue as av on (ob.id=av.object_id) "
-       "join Attribute as a on (av.attr_id=a.id) "
-       "left join Dictionary as d on (d.dict_key=av.uint_value) "
-       "where (a.name = 'Integrado' or a.name = 'HW type' or a.name = 'HW function' or a.name = 'TxType_CKT_ID' or a.name like '%Ref%') "
-       "and ("
-       )
-       i=1
-       for row in vector:
-               obj_id=str(row[1])
-               if i < len_vector:
-                       query2 = query2 + "ob.id = " + obj_id + " or "
-               else:
-                       query2 = query2 + "ob.id = " + obj_id
-               i=i+1
-
-       query = query1 + query2 + ")"
-
-       query3=(
-       "SELECT "
-       "ob.name AS obj1, "
-       "'TBD1', "
-       "concat(ob.name,'_',ip4.name) AS int_name1, "
-       "INET_NTOA(ip4.ip) as ip, "
-       "'TBD2' "
-       "FROM Object AS ob "
-       "JOIN IPv4Allocation AS ip4 ON (ip4.object_id=ob.id) "
-       "where ip4.name = 'system' "
-       "and ("
-       )
-       i=1
-       for row in vector:
-               obj_id=str(row[1])
-               if i < len_vector:
-                       query4 = query4 + "ob.id = " + obj_id + " or "
-               else:
-                       query4 = query4 + "ob.id = " + obj_id
-               i=i+1
-
-       query = query + " UNION " + query3 + query4 + ")"
-
-       return query
-
-# Function that builds a SQL query to obtain the IP interfaces
-def fnc_build_query_interfaces(vector):
-       query1=""
-       query2=""
-       len_vector = len(vector)
-       i=1
-
-       query1=(
-       "SELECT "
-       "ro1.name AS obj1, "
-       "ro1.id AS obj1_id, "
-       "concat(ro1.name,'_',ip4.name) AS int_name1, "
-       "INET_NTOA(ip4.ip) as ip "
-       "FROM "
-       "Object AS ro1 "
-       "JOIN IPv4Allocation AS ip4 ON (ip4.object_id=ro1.id) "
-       "WHERE ("
-       )
-       for row in vector:
-               obj_id=str(row[1])
-               if i < len_vector:
-                       query2 = query2 + "ro1.id = " + obj_id + " or "
-               else:
-                       query2 = query2 + "ro1.id = " + obj_id
-               i=i+1
-
-       query = query1 + query2 + ")"
-
-       return query
-
-
-# Function that builds a SQL query to obtain the connections
-# among routers.
-def fnc_build_query_connections(vector):
-       query1=""
-       query2=""
-       len_vector = len(vector)
-       i=1
-
-       query1=(
-               "SELECT "
-               "ro1.name AS obj1, "
-               "ro1.id as obj1_id, "
-               "concat(ro1.name,'_',p1.label) AS int_name1, "
-               "p1.name AS port1, "
-               "Link.cable, "
-               "p2.name AS port2, "
-               "concat(ro2.name,'_',p2.label) AS int_name2, "
-               "ro2.name AS obj2, "
-               "ro2.id as obj2_id, "
-               "d.dict_value AS obj1type, "
-               "poia.oif_name, "
-               "poib.oif_name "
-               "FROM Object AS ro1 "
-               "JOIN Port AS p1 ON(ro1.id=p1.object_id) "
-               "JOIN Link ON(p1.id=Link.porta) "
-               "JOIN Port AS p2 ON(Link.portb=p2.id) "
-               "JOIN Object AS ro2 ON(p2.object_id=ro2.id) "
-               "JOIN PortOuterInterface AS poia ON(poia.id=p1.type) "
-               "JOIN PortOuterInterface AS poib ON(poib.id=p2.type) "
-               "LEFT JOIN Dictionary AS d ON(ro1.objtype_id=d.dict_key) "
-               "WHERE ("
-       )
-       for row in vector:
-               obj_id=str(row[1])
-               if i < len_vector:
-                       query2 = query2 + "ro1.id = " + obj_id + " or ro2.id = " + obj_id + " or "
-               else:
-                       query2 = query2 + "ro1.id = " + obj_id + " or ro2.id = " + obj_id
-               i=i+1
-
-       query = query1 + query2 + ")"
-
-       return query
-
-
-# Funcion que organiza los puertos de cada nodo
-def fnc_port_list(routers):
-       router_list=[]
-       port_list=[]
-       for router in routers:
-               #print router[0]
-               router_id = router[0][0]
-               for port in router:
-                       port_list.append(port[1])
-               router_list.append((router_id,port_list))
-               port_list=[]
-
-       return router_list
-
-# Function that returns de speed of the port
-def fnc_port_speed(port_string):
-
-       speed=port_string.split('B')
-       speed=speed[0]
-
-       if speed == "100":
-               return "-100Mb"
-       elif speed == "1000":
-               return "-1Gb"
-       elif speed == "10G":
-               return "-10Gb"
-       elif speed == "empty SFP-1000":
-               return "-n/SFP"
-       elif speed == "virtual port":
-               return ""
-       elif speed == "SFP-CES" or speed == "SFP-ATM" or speed == "SFP-ASAP":
-               return "-n/ETH"
-       else:
-               return "-N/A"
-
-# Function that returns the SFP type
-def fnc_port_sfp(port_string):
-
-       if port_string == "virtual port":
-               return "LAG"
-       elif port_string == "SFP-CES" or port_string == "SFP-ATM" or port_string == "SFP-ASAP":
-               return port_string.split('-')[1]
-       else:
-               sfp_type = port_string.split('-')
-               sfp_type = sfp_type[1]
-               return sfp_type
-
-# Function that creates a dictionary for sync references
-# The asignment is done on a port basis
-def fnc_add_atributes_to_dic_ref(attributes):
-
-       dict_ref={}
-
-       for attrib in attributes:
-               node_id=attrib[1]
-               node_ref=attrib[2]
-               if node_ref:
-                       dict_ref[node_id]=node_ref
-               else:
-                       dict_ref[node_id]="N/A"
-
-       return dict_ref
-
-# Function that creates a dictionary with global attributes
-def fnc_add_atributes_to_dic_global(attributes):
-
-       dict_global={}
-
-       for attrib in attributes:
-
-               if "ARSAT" in attrib[0]:
-                       pass
-                       #print attrib
-
-               router_name = attrib[0]
-               attrib_name = attrib[2]
-               system_ip = attrib[3]
-               attrib_value = attrib[4]
-               ckt_id = attrib[3]
-
-               if "HW function" in attrib_name:
-                       hw_function=attrib_value
-                       dict_key=router_name + "_function"
-                       dict_global[dict_key]=hw_function
-               if "Integrado" in attrib_name:
-                       dict_key=router_name + "_Integrado"
-                       dict_global[dict_key]=attrib_value
-               if "Ref_Order" in attrib_name:
-                       dict_key=router_name + "_Ref_Order"
-                       dict_global[dict_key]=attrib_value
-               if "TxType_CKT_ID" in attrib_name:
-                       dict_key=router_name + "_ckt_id"
-                       dict_global[dict_key]=ckt_id
-               if "system" in attrib_name:
-                       dict_key=router_name + "_system"
-                       dict_global[dict_key]=system_ip
-
-       return dict_global
-
-
-# Function that creates a list which holds each router and all its ports.
-# Input: object_connections
-# [('Router1', '1/1/1'), ('Router1', '1/1/2')]
-# Output
-# ('Router1/1/1', {'label': '1/1/1'})
-# The output of this function is used as input to graphviz
-def fnc_node_list(routers,sync_dict, router_mode, graph_hp, graph_lag, graph_cpam):
-
-       temp_list=[]
-
-       for row in routers:
-
-
-               cableID=row[3]
-               if not cableID: cableID=""
-
-               if ("LAG" in cableID.upper() and graph_lag=="n") or ("HAIRPIN" in cableID.upper() and graph_hp=="n") or ("CPAM" in cableID.upper() and graph_cpam=="n"):
-                       a=1
-               else:
-
-                       routerA=row[0]
-                       portA=row[2]
-                       portAspeed=fnc_port_speed(row[10])
-                       portAtype=fnc_port_sfp(row[10])
-                       ipA=row[8]
-                       if not ipA:     ipA="N/A"
-                       nodeA=routerA + "_" + portA
-                       ref1a=sync_dict.get(nodeA,"N/A")
-
-                       routerB=row[5]
-                       portB=row[4]
-                       portBspeed=fnc_port_speed(row[11])
-                       portBtype=fnc_port_sfp(row[11])
-                       ipB=row[9]
-                       if not ipB: ipB="N/A"
-                       nodeB=routerB + "_" + portB
-                       ref1b=sync_dict.get(nodeB,"N/A")
-
-                       if router_mode=="0":
-                               labelA="<"+ portA + "<BR />" + portAtype + portAspeed + "<BR />" + ipA + "<BR />" + ref1a +">"
-                               labelB="<"+ portB + "<BR />" + portBtype + portBspeed + "<BR />" + ipB + "<BR />" + ref1b +">"
-                       elif router_mode=="1" or router_mode=="2":
-                               labelA= portA + "&#92;n" + portAtype + portAspeed + "&#92;n" + ipA + "&#92;n" + ref1a
-                               labelB= portB + "&#92;n" + portBtype + portBspeed + "&#92;n" + ipB + "&#92;n" + ref1b
-                       elif router_mode=="3":
-                               labelA=""
-                               labelB=""
-
-                       temp_list.append((routerA,nodeA,{'label':labelA}))
-                       temp_list.append((routerB,nodeB,{'label':labelB}))
-
-       # List will be ordered and sorted always by the first field
-       # which is the router name
-       lista_sorted=sorted(temp_list, key=itemgetter(0))
-       lista_grouped = groupby(lista_sorted, key=itemgetter(0))
-
-       a = []
-       for i,rou in enumerate(lista_grouped):
-               a.append(list(rou[1]))
-
-       return a
-
-# Function that crosses the connections and interfaces to come out
-# with a proper list
-#
-# Output:
-#('Router1', 105L, '1/1/7', None, '2/2/10', 'Router2', 418L, 'Router', '10.2.34.113', '10.2.34.114', '1000Base-T', '1000Base-T')
-#
-def fnc_cross_conn_inter(connections,interfaces):
-       connection_list=[]
-
-       for conn in connections:
-
-               name1=conn[0]
-               id1=conn[1]
-               p1=conn[3]
-               cable=conn[4]
-               p2=conn[5]
-               name2=conn[7]
-               id2=conn[8]
-               router_type=conn[9]
-               ip1=""
-               ip2=""
-               p1t=conn[10]
-               p2t=conn[11]
-
-               int1=conn[2]
-               int2=conn[6]
-
-               for interface in interfaces:
-                       int_name=interface[2]
-                       ip=interface[3]
-                       if int1==int_name:
-                               ip1=ip
-                               break
-                       else:
-                               ip1="N/A"
-
-               for interface in interfaces:
-                       int_name=interface[2]
-                       ip=interface[3]
-                       if int2==int_name:
-                               ip2=ip
-                               break
-                       else:
-                               ip2="N/A"
-
-               connection_list.append((name1,id1,p1,cable,p2,name2,id2,router_type,ip1,ip2,p1t,p2t,int1,int2))
-
-       #fnc_print_list(connection_list)
-
-       return connection_list
-
-
-# Function that builds a list which holds the connections among routers.
-# The output of this function is used as input to graphviz
-def fnc_edge_list(vector, graph_lag, graph_hp, graph_cpam, router_mode):
-       edge_list=[]
-       for row in vector:
-               routerA=row[0]
-               portA=row[2]
-               routerB=row[5]
-               portB=row[4]
-               cableID=row[3]
-               nodeA=routerA + "_" + portA
-               nodeB=routerB + "_" + portB
-
-               if not cableID: cableID=""
-
-               #print nodeA, cableID, nodeB
-
-               if ("LAG" in cableID.upper() and graph_lag=="n") or ("HAIRPIN" in cableID.upper() and graph_hp=="n") or ("CPAM" in cableID.upper() and graph_cpam=="n"):
-                       a=1
-               else:
-                       edge_list.append(((nodeA,nodeB),{'label':cableID}))
-
-       return edge_list
-
-# Verifies that an object exists
-def fnc_check_for_topo(objList):
-       if len(objList) == 0:
-               return 0
-       else:
-               return 1
-
-# Function to print lists
-def fnc_print_list(vector):
-       for vec in vector:
-               print vec
-
-# Function to obtain topology name
-def fnc_build_topo_name(vector):
-       topo_name=""
-       len_vector= len(vector)
-       i=1
-       for tn in vector:
-               if i < len_vector:
-                       topo_name=topo_name+tn+"-"
-               else:
-                       topo_name=topo_name+tn
-               i=i+1
-
-       return topo_name
-
-# Function that returns the color of the router depending on its
-# situation
-def fnc_router_color(router_function,router_int,router_name):
-
-       # Ref_Order
-       router_sync_order=global_dict.get(router_name+"_Ref_Order","N/A")
-
-       # Color depending on function
-       if router_function == "High-Ran":
-               return 'lightblue4'
-       elif router_function == "Mid-Ran":
-               return 'lightpink4'
-       elif "si" in router_int:
-               # color depending on Ref_Order
-               if "ref1 ref2" in router_sync_order:
-                       return 'lightblue3'
-               elif "ref2 ref1" in router_sync_order:
-                       return 'lightblue1'
-               else:
-                       return 'grey'
-       elif "TX" in router_function:
-               return 'yellow'
-       # Color depending on integration
-       elif router_int=="no":
-               return 'orange'
-       elif router_int=="out-of-service" or router_int=="desinsertado":
-               return 'red'
-       else:
-               return 'grey'
-
-# Function that returns metadata of the router
-def fnc_router_metadata(global_dict,router_name,what, router_function, router_ckt_id, router_mode):
-
-       router_sync_order=global_dict.get(router_name+"_Ref_Order","N/A")
-       router_ip=global_dict.get(router_name+"_system","N/A")
-
-       if "TX" in router_function:
-
-               if what=="labelHtml":
-
-                       router_label=(
-                               "<"+
-                               "<font point-size=\"10\">"+router_ckt_id+"</font>"+"<BR />"
-                               +">"
-                               )
-                       return router_label
-
-               elif what=="labelText":
-
-                       router_label = router_ckt_id
-                       return router_label
-
-       else:
-
-               if what=="labelHtml":
-
-                       if router_mode=="3":
-                               router_label=(
-                                       "<"+
-                                       "<font point-size=\"10\">"+router_name+"</font>"+"<BR />"+
-                                       "<font point-size=\"9\">" +router_ip+"</font>"+"<BR />"
-                                       +">"
-                                       )
-                               return router_label
-
-                       else:
-                               router_label=(
-                                       "<"+
-                                       "<font point-size=\"10\">"+router_name+"</font>"+"<BR />"+
-                                       "<font point-size=\"9\">" +router_ip+"</font>"+"<BR />"+
-                                       "<font point-size=\"9\">" +router_sync_order+"</font>"
-                                       +">"
-                                       )
-                               return router_label
-
-               elif what=="labelText":
-
-                       if router_mode=="3":
-                               router_label = router_name + "&#92;n" + router_ip
-                               return router_label
-                       else:
-                               router_label = router_name + "&#92;n" + router_ip + "&#92;n" + router_sync_order
-                               return router_label
-
-
-
-# Function that returns port_string when router as a node
-def fnc_port_string(router_label, port_string, color, router_mode, router_function):
-
-       port_string=port_string[1:]
-       temp_port = port_string.split("|")
-
-       if "TX" in router_function:
-
-               if router_function == "TX_MIX":
-
-                       temp_string=""
-
-                       for port in port_string.split("|"):
-                               temp_string = temp_string + port.split("\n")[0] + "|"
-
-                       port_string = temp_string[:-1]
-
-                       temp_string = "{" + port_string + "}"
-                       temp_string = " [" + color + ",label=\"" + temp_string + "\"]"
-                       return temp_string
-
-               elif router_function == "TX_ARSAT":
-
-                       #print router_label
-
-                       temp_string = "{" + router_label + "}"
-                       temp_string = " [" + color + ",label=\"" + temp_string + "\"]"
-                       return temp_string
-
-       else:
-
-               if router_mode=="1":
-                       temp_string = "{" + router_label + "|" + port_string + "}"
-               elif router_mode=="2":
-                       temp_string = "{" + router_label + "|" + "{" + port_string + "}" + "}"
-               elif router_mode=="3":
-                       temp_string = router_label
-
-               temp_string = " [" + color + ",label=\"" + temp_string + "\"]"
-               return temp_string
-
-
-########################################################################
-# Program
-########################################################################
-
-db = MySQLdb.connect(host="10.10.61.10",       # your host, usually localhost
-                                        port=3306,
-                                        user="root",                   # your username
-                                        passwd="mysqlroot",    # your password
-                                        db="racktables")               # name of the data base
-
-posProg        = 0
-posTopo        = 1
-posMode                = 2
-posFormat      = 3
-posAlgo                = 4
-posDirect      = 5
-posLine                = 6
-posAggreg      = 7
-#posLag                = 8
-#posHairPin    = 9
-#posCPAM       = 10
-
-# Check for inline parameters
-if len(sys.argv)<8:
-       print "Not enough paramteres. Quitting..."
-       sys.exit(-1)
-
-# Getting topo name
-topo_name = sys.argv[posTopo]
-topo_name = topo_name.upper()
-topo_name = topo_name.split(",")
-
-#==================================================================
-#==================================================================
-# query0 obtains the Id of the tag_name.
-
-query0 = fnc_build_query_topo_id(topo_name)
-
-cur = db.cursor()
-cur.execute(query0)
-topo_id = list(cur.fetchall())
-if fnc_check_for_topo(topo_id) == 0:
-       print "Topology not found. Quitting..."
-       sys.exit(-1)
-
-#==================================================================
-#==================================================================
-# query10 obtains the IDs of routers that have tag 'topo_name'
-# The result is the following.
-
-#(objeto_name, object_id)
-
-query10 = fnc_build_query_objetos(topo_id)
-
-cur = db.cursor()
-cur.execute(query10)
-object_list = list(cur.fetchall())
-
-#==================================================================
-#==================================================================
-# query15 obtains the attributes of the routers that have tag
-# 'topo_name'.
-# It also brings de system IP of the router.
-# The result is the following.
-
-#('Router1', 'Router1_1/1/1', 'Sync_Ref1', '1/1/1', None, '10.2.21.168')
-#('Router1', 'Router1_1/1/2', 'Sync_Ref2', '1/1/2', None, '10.2.21.168')
-#('Router1', None, 'Sync_Ref_Order', None, 'ref1 ref2 external', '10.2.21.168')
-#('Router1', None, 'Integrado', None, 'si', '10.2.21.168')
-
-query15=fnc_build_query_attributes(object_list)
-cur=db.cursor()
-cur.execute(query15)
-attr_list = list(cur.fetchall())
-sync_dict = fnc_add_atributes_to_dic_ref(attr_list)
-global_dict = fnc_add_atributes_to_dic_global(attr_list)
-
-#==================================================================
-#==================================================================
-# query20 brings the connection among objects.
-# This query also brings connections to routers that do not have the
-# the requested tag.
-# The result is the following.
-
-#(Router1, port1, cableID, port1, Router2)
-
-#('Router1', 172L, 'Router1_RTR1toRTR2_1_1G', '1/6/8', None, '2/2/14', 'Router2_RTR2toRTR1_1_1G', 'Router2', 418L, 'Router', '1000Base-T', '1000Base-T')
-
-query20=fnc_build_query_connections(object_list)
-cur = db.cursor()
-cur.execute(query20)
-object_connections = list(cur.fetchall())
-
-#==================================================================
-#==================================================================
-# query25 brings the connection among objects.
-# This query obtains the interfaces and IP addresses.
-
-# (Router, ID, Interface_name, IP)
-
-query25=fnc_build_query_interfaces(object_list)
-cur = db.cursor()
-cur.execute(query25)
-object_interfaces = list(cur.fetchall())
-
-#==================================================================
-#==================================================================
-# The function fnc_cross_conn_inter(.) crosses connections with
-# interfaces to come out with the following information
-
-#(Router1, port1, cableID, port1, Router2)
-#('Router1', 105L, '1/1/7', None, '2/2/10', 'Router2', 418L, 'Router', '10.2.34.113', '10.2.34.114', '1000Base-T', '1000Base-T')
-
-object_connections=fnc_cross_conn_inter(object_connections,object_interfaces)
-
-#==================================================================
-#==================================================================
-# The function fnc_remove_routers_wotag(.) filters out the data
-# obtained with query20 in such a way that only the connections
-# to routers with the requested tag will remain.
-# The result is the following.
-
-#(Router1, port1, cableID, port1, Router2)
-#('Router1', 105L, '1/1/7', None, '2/2/10', 'Router2', 418L, 'Router', '10.2.34.113', '10.2.34.114', '1000Base-T', '1000Base-T')
-
-object_connections=fnc_remove_routers_wotag(object_list,object_connections)
-
-#==================================================================
-# The graph is created.
-#==================================================================
-
-# Format Dictionaries
-mode_dict              = {"0":"cluster",       "1":"one-line", "2":"two-lines","3":"only-names"}
-format_dict    = {"0":"png",           "1":"svg"}
-algo_dict              = {"0":"dot",           "1":"fdp",              "2":"circo",    "3":"twopi",    "4":"neato"}
-rankdir_dict   = {"0":"LR",            "1":"TB"}
-lines_dict             = {"0":"line",          "1":"true",             "2":"ortho",    "3":"polyline"}
-aggr_dict              = {"0":"n",                     "1":"y"}
-port_dict              = {}
-
-router_mode            = sys.argv[posMode]
-output_format          = sys.argv[posFormat]
-output_algo                    = sys.argv[posAlgo]
-output_direction       = sys.argv[posDirect]
-output_line                    = sys.argv[posLine]
-aggregator                     = sys.argv[posAggreg]
-graph_lag                      = "n"
-graph_hp                       = "n"
-graph_cpam                     = "n"
-
-#print "mode", mode_dict[router_mode]
-#print "format", format_dict[output_format]
-#print "algori", algo_dict[output_algo]
-#print "direcc", rankdir_dict[output_direction]
-#print "line", lines_dict[output_line]
-#print "aggr", aggr_dict[aggregator]
-
-#==================================================================
-#==================================================================
-# At this instance of the run, the list object_connections[] only has
-# connections to routers that do have the requested tag.
-# The function fnc_edge_list(.) reorders that information
-# so it will be easier to feed graphviz.
-
-#((Router1_port1, Router2_port1), {label: cableID})
-
-edges=fnc_edge_list(object_connections, graph_lag, graph_hp, graph_cpam, router_mode)
-
-#===================================================================
-#===================================================================
-# The list edges[] holds the connections among routers that do have
-# the requested tag.
-# With this information we filter contruct a new list grouping ports
-# per router.
-
-#(Router1, Router1_portX, {'label':""}),(Router2, Router2_portY, {'label':""})
-#('Router1', 'Router1_1/2/7', {'label': '1/2/7\nT-1Gb\n10.2.61.146\nSync_Ref1'}), ('Router2', 'Router2_1/2/8', {'label': '1/2/8\nT-1Gb\n10.2.61.149\nSync_Ref2'})
-
-routers=fnc_node_list(object_connections,sync_dict, router_mode, graph_hp, graph_lag, graph_cpam)
-
-#===================================================================
-#===================================================================
-# Gegin the plot
-
-g0 = gv.Graph(format=format_dict[output_format], engine=algo_dict[output_algo])
-
-topo = '\"'+fnc_build_topo_name(topo_name)+'\"'
-
-g0.body.append('label='+topo)
-g0.body.append('rankdir='+rankdir_dict[output_direction])
-#g0.body.append('rank=min')
-g0.body.append('splines='+lines_dict[output_line])
-g0.node_attr['style']='filled'
-g0.node_attr['fixedsize']='false'
-g0.node_attr['fontsize']='9'
-
-if router_mode=="0":
-       g0.node_attr['shape']='box'
-       labelType="labelHtml"
-elif router_mode=="1" or router_mode=="2" or router_mode=="3":
-       g0.body.append('overlap=false')
-       g0.node_attr['shape']='Mrecord'
-       g0.node_attr['overlap']='false'
-       labelType="labelText"
-
-if aggregator == "1":
-       g10 = gv.Graph('cluster_hr')
-       g20 = gv.Graph('cluster_mr')
-       g25 = gv.Graph('cluster_tx')
-       g30 = gv.Graph('cluster_lr', engine=algo_dict[output_algo])
-
-       g10.body.append('rankdir=TB')
-       g10.body.append('label=\"HR\"')
-
-       g20.body.append('rankdir=TB')
-       g20.body.append('label=\"MR\"')
-
-       g30.body.append('rankdir=TB')
-       g30.body.append('label=\"LR\"')
-
-if router_mode=="0":
-       i = 1
-       for router in routers:
-               # Variables
-               router_name = router[0][0]
-               router_function=global_dict.get(router_name+"_function","N/A")
-               router_int=global_dict.get(router_name+"_Integrado","N/A")
-               router_ckt_id=global_dict.get(router_name+"_ckt_id","N/A")
-               router_label=fnc_router_metadata(global_dict,router_name,labelType, router_function, router_ckt_id, router_mode)
-               router_color=fnc_router_color(router_function,router_int,router_name)
-
-               #print router_name, router_function
-
-               # Parametrization
-               cluster_name = "cluster"+str(i)
-               c = gv.Graph(cluster_name)
-               c.body.append('label='+router_label)
-               c.body.append('shape=box')
-               c.body.append('style=filled')
-
-               # Color depending on function in network
-               c.body.append('fillcolor='+router_color)
-               c.node_attr.update(style='filled')
-
-               # Ports workout
-               for port in router:
-
-                       node_id=port[1]
-                       if ":" in node_id: node_id=node_id.replace(":","#")
-                       port_id=port[2]['label']
-                       c.node(node_id,label=port_id)
-
-               # AsignaciĆ³n al cluster Low o High Run
-               if aggregator == "1":
-                       if router_function == "High-Ran":
-                               g10.subgraph(c)
-                       elif router_function == "Mid-Ran":
-                               g20.subgraph(c)
-                       else:
-                               g30.subgraph(c)
-
-                       g0.subgraph(g10)
-                       g0.subgraph(g20)
-                       g0.subgraph(g30)
-
-               # No grouping
-               else:
-                       g0.subgraph(c)
-
-               i=i+1
-
-       for e in edges:
-               edgeA=e[0][0]
-               if ":" in edgeA: edgeA=edgeA.replace(":","#")
-               edgeB=e[0][1]
-               if ":" in edgeB: edgeB=edgeB.replace(":","#")
-               edgeLabel=e[1]['label']
-               g0.edge_attr['fontsize']='9'
-               g0.edge(edgeA,edgeB,label=edgeLabel)
-
-elif router_mode=="1" or router_mode=="2" or router_mode=="3":
-       i = 1
-       for router in routers:
-               # Variables
-               router_name = router[0][0]
-               router_function=global_dict.get(router_name+"_function","N/A")
-               router_int=global_dict.get(router_name+"_Integrado","N/A")
-               router_ckt_id=global_dict.get(router_name+"_ckt_id","N/A")
-               router_label=fnc_router_metadata(global_dict,router_name,labelType, router_function, router_ckt_id, router_mode)
-               router_color=fnc_router_color(router_function,router_int,router_name)
-
-               # Parametrization
-               struct_name = "struct"+str(i)
-
-               # Color depending on function in network
-               color= 'fillcolor='+router_color
-
-               # Ports workout
-               p=1
-               port_string=""
-               for port in router:
-
-                       node_id=port[1]
-                       if ":" in node_id: node_id=node_id.replace(":","#")
-                       port_id=port[2]['label']
-
-                       port_string=port_string+"|<f"+str(p)+">"+port_id
-                       dict_key = str(i)+"_"+str(p)
-                       port_dict[node_id]=dict_key
-
-                       p=p+1
-
-               node_string = fnc_port_string(router_label, port_string, color, router_mode, router_function)
-
-               # AsignaciĆ³n al cluster Low o High Run
-               if aggregator == "1":
-                       if router_function == "High-Ran": g10.body.append(struct_name+node_string)
-                       elif router_function == "Mid-Ran": g20.body.append(struct_name+node_string)
-                       else: g30.body.append(struct_name+node_string)
-                       g0.subgraph(g10)
-                       g0.subgraph(g20)
-                       g0.subgraph(g30)
-
-               # No grouping
-               else:
-                       g0.body.append(struct_name+node_string)
-
-               i=i+1
-
-       for e in edges:
-               tempA=e[0][0]
-               if ":" in tempA: tempA=tempA.replace(":","#")
-               tempA=port_dict[tempA].split("_")
-               if router_mode=="3":
-                       edgeA="struct"+tempA[0]
-               else:
-                       edgeA="struct"+tempA[0]+":f"+tempA[1]
-
-               tempB=e[0][1]
-               if ":" in tempB: tempB=tempB.replace(":","#")
-               tempB=port_dict[tempB].split("_")
-               if router_mode=="3":
-                       edgeB="struct"+tempB[0]
-               else:
-                       edgeB="struct"+tempB[0]+":f"+tempB[1]
-
-               edgeLabel=e[1]['label']
-               g0.edge_attr['fontsize']='9'
-               g0.edge(edgeA,edgeB,label=edgeLabel)
-
-filename=fnc_build_filename(topo_name)
-print filename + "." + format_dict[output_format]
-g0.render(filename)
diff --git a/python-graph-topology/draw_topo_26_estable.py b/python-graph-topology/draw_topo_26_estable.py
new file mode 100755 (executable)
index 0000000..9687de5
--- /dev/null
@@ -0,0 +1,384 @@
+# coding=utf-8\r
+##########################################################\r
+# Name: draw_topo_02.py\r
+# Version: 0.2\r
+# Author: Lucas Aimaretto\r
+# Date: 14-jun-2015\r
+#\r
+# - 0.1:       first draft\r
+#                      This version will graph any topology based on the tags of the routers.\r
+# - 0.2:       Reorder of functions; cleaning of code.\r
+# - 0.3:       Implementing of IP/PORT/Speed information. Change on function\r
+#                      fnc_build_query_connections SQL's query\r
+# - 0.4:       Included sync-e reference to each port. If not abailable, then N/A is shown.\r
+#                      For this, a sync_dict is created.\r
+# - 0.5:       Including system IP, sync order, color for not integrated routers.\r
+# - 0.6:       If no SFP, no speed can be obtained. Then "No SFP" is shown. If CES, ATM or ASAP, then "No ETH" is shown.\r
+# - 0.7:       fnc_build_query_objetos(.) modify to further filter out objects with tags (and no ipvnet)\r
+#                      fnc_build_query_interfaces(.) to bring IPs and interfaces\r
+#                      fnc_build_query_connections(.) now only brings connections and no IPs\r
+#                      fnc_cross_conn_inter(.) finds out IP for connections\r
+# - 0.8:       Asked whether to graph LAGs or not\r
+#                      TBD: consider when link label is something else than "LAG", "Hairpin" or "".\r
+# - 1.1:       Distinction between High, Mid and Low Ran\r
+# - 1.2:       Reducing font size of link's labels\r
+# - 1.3:       Including FO and ARSAT as possible labels for links\r
+# - 1.7:       Different colors for MR and HR\r
+# - 1.8:       Includes transmission with a list\r
+# - 1.9:       Ring topology now available\r
+# - 2.0:       Change Name of file to match Claro's format.\r
+# - 2.1:       Bug regarding getting the system IP of router: fnc_build_query_attributes(.)\r
+#                      TxType now considered when MIX TX is needed (ie: DWDM+MW)\r
+# - 2.2:       Option to graph nodes with the names, only.\r
+# - 2.3:       implementing argv to pass parameters in line\r
+#                      change \n to &#92;n in port an router when mode 1,2,3\r
+# - 2.4:       full custimoization via argv[]\r
+#                      Different color depending con Ref_Order\r
+\r
+#!/usr/bin/python\r
+import MySQLdb\r
+import graphviz as gv\r
+import pydot\r
+import time\r
+import sys\r
+import functools\r
+import datetime\r
+import pandas as pd \r
+import networkx as nx\r
+from sql_definitions import *\r
+from functions import *\r
+\r
+#  python -m nuitka draw_topo_26_estable.py --nofollow-import-to=MySQLdb --nofollow-import-to=graphviz --nofollow-import-to=pydot --nofollow-import-to=time --nofollow-import-to=sys --nofollow-import-to=functools --nofollow-import-to=datetime --nofollow-import-to=pandas --nofollow-import-to=networkx --nofollow-import-to=operator --nofollow-import-to=itertools --nofollow-import-to=re --nofollow-import-to=matplotlib --follow-imports\r
+#\r
+pd.set_option('display.max_rows', 500)\r
+pd.set_option('display.max_columns', 500)\r
+pd.set_option('display.width', 1000)\r
+\r
+import matplotlib\r
+matplotlib.use('Agg')\r
+import matplotlib.pyplot as plt\r
+\r
+graph_lag=graph_hp=graph_cpam='n'\r
+router_mode='3'\r
+topos_names=['co008_016']\r
+\r
+########################################################################\r
+# Globals\r
+########################################################################\r
+\r
+ipran_tx = ["LAG_Y","HAIRPIN_Y","SDH","RADIO","DWDM","CDWM","FO",""]\r
+version_script="21"\r
+\r
+########################################################################\r
+# Program\r
+########################################################################\r
+\r
+db = MySQLdb.connect(host="127.0.0.1", port=3306, user="viewRT", passwd="viewRT", db="racktables")\r
+\r
+posProg        = 0\r
+posTopo        = 1\r
+posMode                = 2\r
+posFormat      = 3\r
+posAlgo                = 4\r
+posDirect      = 5\r
+posLine                = 6\r
+posAggreg      = 7\r
+posLag         = 8\r
+posNodeSep  = 9\r
+posRankSep  = 10\r
+#posHairPin    = 9\r
+#posCPAM       = 10\r
+\r
+# Check for inline parameters\r
+if len(sys.argv)<9:\r
+       print "Not enough paramteres. Quitting..."\r
+       sys.exit(-1)\r
+\r
+# Getting topo and routers name\r
+input_string = sys.argv[posTopo]\r
+input_string = input_string.upper()\r
+input_string = input_string.split(",")\r
+\r
+# We distinguis if we have topos and/or routers\r
+topos_names,routers_names = fnc_input_string_type(input_string)\r
+#print "topos: ",len(topos_names),"; routers: ",len(routers_names)\r
+\r
+# In this list wwe'll save the object_id's\r
+object_list            = []\r
+object_list_topos      = []\r
+object_list_routers    = []\r
+df_object_list_topos   = pd.DataFrame()\r
+df_object_list_routers = pd.DataFrame()\r
+\r
+#==================================================================\r
+#==================================================================\r
+# query10 obtains the IDs of routers that have tag 'input_string'\r
+# The result is the following.\r
+if len(topos_names) > 0:\r
+\r
+       # query0 obtains the Id of the tag_name.\r
+       query0 = fnc_build_query_topo_id(topos_names)\r
+       cur    = db.cursor()\r
+       cur.execute(query0)\r
+       topo_id = list(cur.fetchall())\r
+\r
+       if len(topo_id) > 0:\r
+               query10 = fnc_build_query_objetos(topo_id)\r
+               df_object_list_topos = pd.read_sql(query10,db)\r
+\r
+       else:\r
+               sys.exit(-1)\r
+\r
+#==================================================================\r
+#==================================================================\r
+# query11 obtains the IDs of routers that have tag 'routers_names'\r
+# The result is the following.\r
+if len(routers_names) > 0:\r
+       query11 = fnc_build_query_objetos_name(routers_names)\r
+       df_object_list_routers = pd.read_sql(query11,db)\r
+\r
+\r
+# We add together topos and routers\r
+#object_list    = object_list_topos + object_list_routers\r
+df_object_list = pd.concat([df_object_list_topos,df_object_list_routers])\r
+\r
+\r
+#==================================================================\r
+#==================================================================\r
+# query25 obtains the interfaces and IP addresses.\r
+query25=fnc_build_query_interfaces(df_object_list)\r
+df_object_interfaces = pd.read_sql(query25,db)\r
+\r
+# We grab routers with their system or loopback interfaces.\r
+df_system = df_object_interfaces[(df_object_interfaces.intName == 'system') | (df_object_interfaces.intName == 'System') | (df_object_interfaces.intName == 'loopback')]\r
+df_system = df_system[['name','ip']]\r
+df_system = pd.merge(df_object_list,df_system,on=['name'],how='left')\r
+\r
+#==================================================================\r
+#==================================================================\r
+# query20 brings the connection among objects.\r
+# This query also brings connections to routers that do not have the\r
+# the requested tag.\r
+query20 = fnc_build_query_connections(df_object_list)\r
+df_object_connections = pd.read_sql(query20,db)\r
+\r
+dfConn = pd.merge(df_system,df_object_connections,left_on=['name'],right_on=['name1'])\r
+dfConn = pd.merge(df_system,dfConn,               left_on=['name'],right_on=['name2'])\r
+dfConn = dfConn[["name1","port1","cable","port2","name2","obj1type","obj2type","port1Speed","port2Speed","intName1","intName2"]]\r
+\r
+# We merge both connections and interfaces so we stay with informatino of routers with proper tag\r
+dfConnFinal = pd.merge(dfConn,     df_object_interfaces, left_on=['name1','intName1'], right_on=['name','intName'], how='left')\r
+dfConnFinal = pd.merge(dfConnFinal,df_object_interfaces, left_on=['name2','intName2'], right_on=['name','intName'], how='left')\r
+dfConnFinal = dfConnFinal.fillna("N/A")\r
+dfConnFinal = dfConnFinal[["name1","port1","cable","port2","name2","obj1type","obj2type","port1Speed","port2Speed","intName1","intName2","ip_x","ip_y"]]\r
+dfConnFinal = dfConnFinal.drop_duplicates()\r
+\r
+#==================================================================\r
+#==================================================================\r
+# query15 obtains the attributes of the routers whose Ids are in 'object_list'\r
+# It also brings de system IP of the router.\r
+query15 = fnc_build_query_attributes(df_object_list)\r
+df_attr_list = pd.read_sql(query15, db)\r
+df_attr_list = df_attr_list.apply(setFinalValue, axis=1)\r
+df_attr_list = df_attr_list.drop(['string_value','dict_value'], axis=1)\r
+df_attr_list = df_attr_list.pivot(index='name',columns='attrName',values='finalValue').reset_index()\r
+df_attr_list.columns = [x.replace(" ","") for x in df_attr_list.columns]\r
+df_attr_list = pd.merge(df_system, df_attr_list, on=['name'], how='left')\r
+df_attr_list = df_attr_list.fillna("N/A")\r
+\r
+#==================================================================\r
+#==================================================================\r
+# BUild global dictionaries\r
+global_dict = fnc_add_atributes_to_dic_global(df_attr_list)\r
+\r
+\r
+#==================================================================\r
+# The graph is created.\r
+#==================================================================\r
+\r
+# Format Dictionaries\r
+mode_dict              = {"0":"cluster",       "1":"one-line", "2":"two-lines", "3":"only-names", "4":"networkx"}\r
+format_dict    = {"0":"png",           "1":"svg"}\r
+algo_dict              = {"0":"dot",           "1":"fdp",              "2":"circo",    "3":"twopi",    "4":"neato"}\r
+rankdir_dict   = {"0":"LR",            "1":"TB"}\r
+lines_dict             = {"0":"line",          "1":"true",             "2":"ortho",    "3":"polyline"}\r
+aggr_dict              = {"0":"n",                     "1":"y"}\r
+lag_dict               = {"0":"n",                     "1":"y"}\r
+port_dict              = {}\r
+\r
+router_mode            = sys.argv[posMode]\r
+output_format          = sys.argv[posFormat]\r
+output_algo                    = sys.argv[posAlgo]\r
+output_direction       = sys.argv[posDirect]\r
+output_line                    = sys.argv[posLine]\r
+aggregator                     = sys.argv[posAggreg]\r
+graph_lag                      = lag_dict[sys.argv[posLag]]\r
+nodesep                                = sys.argv[posNodeSep]\r
+ranksep                                = sys.argv[posRankSep]\r
+graph_hp                       = "n"\r
+graph_cpam                     = "n"\r
+\r
+#==================================================================\r
+#==================================================================\r
+# At this instance of the run, the list object_connections[] only has\r
+# connections to routers that do have the requested tag.\r
+# The function fnc_edge_list(.) reorders that information\r
+# so it will be easier to feed graphviz.\r
+edges   = fnc_edge_list(dfConnFinal, graph_lag, graph_hp, graph_cpam, router_mode)\r
+routers = fnc_node_list(dfConnFinal, global_dict, router_mode, graph_hp, graph_lag, graph_cpam)\r
+\r
+#===================================================================\r
+#===================================================================\r
+#print "router-mode ", router_mode, "format ", format_dict[output_format], "algo ", algo_dict[output_algo], sys.argv[posNodeSep], sys.argv[posRankSep]\r
+# Gegin the plot\r
+if router_mode  in ['0','1','2','3']:\r
+\r
+       g0 = gv.Graph(format=format_dict[output_format], engine=algo_dict[output_algo])\r
+\r
+       topo = '\"'+fnc_build_topo_name(input_string)+'\"'\r
+\r
+       g0.body.append('label='  +topo)\r
+       g0.body.append('rankdir='+rankdir_dict[output_direction])\r
+       g0.body.append('splines='+lines_dict[output_line])\r
+\r
+       g0.node_attr['style']     = 'filled'\r
+       g0.node_attr['fixedsize'] = 'false'\r
+       g0.node_attr['fontsize']  = '9'\r
+\r
+       if router_mode == '0':\r
+\r
+               g0.node_attr['shape'] = 'box'\r
+               labelType="labelHtml"\r
+\r
+       elif router_mode in ['1','2','3']:\r
+\r
+               g0.body.append('overlap=false')\r
+               g0.body.append('nodesep='+nodesep)\r
+               g0.body.append('ranksep='+ranksep)\r
+\r
+               g0.node_attr['shape']   = 'Mrecord'\r
+               g0.node_attr['overlap'] = 'false'\r
+\r
+               labelType="labelText"\r
+\r
+       i = 1\r
+\r
+       for router in routers:\r
+\r
+               # Variables\r
+               router_name     = router[0][0]\r
+               router_function = get_attribute(router_name,"HWfunction",global_dict)\r
+               router_int      = get_attribute(router_name,"Integrado",global_dict)\r
+               router_ckt_id   = get_attribute(router_name,"ckt_id",global_dict)\r
+               router_color    = get_attribute(router_name,"color",global_dict)['graphviz']\r
+               router_label    = fnc_router_metadata(global_dict,router_name, labelType, router_function, router_ckt_id, router_mode)\r
+\r
+               if router_mode == '0':\r
+\r
+                       # Parametrization\r
+                       cluster_name = "cluster"+str(i)\r
+                       c = gv.Graph(cluster_name)\r
+                       c.body.append('label='+router_label)\r
+                       c.body.append('shape=box')\r
+                       c.body.append('style=filled')\r
+\r
+                       # Color depending on function in network\r
+                       c.body.append('fillcolor='+router_color)\r
+                       c.node_attr.update(style='filled')\r
+\r
+                       # Ports workout\r
+                       for port in router:\r
+                               node_id = port[1]\r
+                               if ":" in node_id: \r
+                                       node_id = node_id.replace(":","#")\r
+                               port_id = port[2]['label']\r
+                               c.node(node_id,label=port_id)\r
+\r
+                       g0.subgraph(c)\r
+\r
+               elif router_mode in ['1','2','3']:\r
+\r
+                       # Parametrization\r
+                       struct_name = "struct"+str(i)\r
+\r
+                       # Color depending on function in network\r
+                       color = 'fillcolor='+router_color\r
+\r
+                       # Ports workout\r
+                       p=1\r
+                       port_string=""\r
+                       for port in router:\r
+\r
+                               node_id=port[1]\r
+                               if ":" in node_id: node_id=node_id.replace(":","#")\r
+                               port_id=port[2]['label']\r
+\r
+                               port_string=port_string+"|<f"+str(p)+">"+port_id\r
+                               dict_key = str(i)+"_"+str(p)\r
+                               port_dict[node_id]=dict_key\r
+\r
+                               p=p+1\r
+\r
+                       node_string = fnc_port_string(router_label, port_string, color, router_mode, router_function)\r
+\r
+                       g0.body.append(struct_name+node_string)                 \r
+\r
+               i=i+1\r
+\r
+       for e in edges:\r
+\r
+               if router_mode == '0':\r
+\r
+                       edgeA = e[0][0]\r
+                       if ":" in edgeA:\r
+                               edgeA = edgeA.replace(":","#")\r
+                       edgeB = e[0][1]\r
+                       if ":" in edgeB:\r
+                               edgeB = edgeB.replace(":","#")\r
+                       edgeLabel = e[1]['label']\r
+                       edgeSpeed = e[2]\r
+\r
+               elif router_mode in ['1','2','3']:\r
+\r
+                       tempA = e[0][0]\r
+                       if ":" in tempA:\r
+                               tempA=tempA.replace(":","#")\r
+                       tempA = port_dict[tempA].split("_")\r
+\r
+                       if router_mode =="3":\r
+                               edgeA = "struct"+tempA[0]\r
+                       else:\r
+                               edgeA = "struct"+tempA[0]+":f"+tempA[1]\r
+\r
+                       tempB = e[0][1]\r
+                       if ":" in tempB:\r
+                               tempB=tempB.replace(":","#")\r
+                       tempB = port_dict[tempB].split("_")\r
+\r
+                       if router_mode == "3":\r
+                               edgeB = "struct"+tempB[0]\r
+                       else:\r
+                               edgeB = "struct"+tempB[0]+":f"+tempB[1]\r
+\r
+                       edgeLabel=e[1]['label']\r
+                       edgeSpeed=e[2]\r
+\r
+               g0.edge_attr['fontsize']='9'\r
+               g0.edge(edgeA,edgeB,label=edgeLabel, color=fnc_edge_format(edgeLabel, "color", edgeSpeed), penwidth=fnc_edge_format(edgeLabel,"width",edgeSpeed))\r
+\r
+\r
+       if len(topos_names) > 0:\r
+               filename=fnc_build_filename(topos_names)\r
+       elif len(routers_names) > 0:\r
+               filename=fnc_build_filename("ROUTERS")\r
+\r
+       #print filename + "." + format_dict[output_format]\r
+       print filename\r
+       g0.render(filename)\r
+\r
+       # We now build the graphml\r
+       if router_mode in ['1','2','3']:\r
+               edges   = fnc_edge_list(dfConnFinal, graph_lag, graph_hp, graph_cpam, '4')\r
+               routers = fnc_node_list(dfConnFinal, global_dict, '4', graph_hp, graph_lag, graph_cpam)\r
+\r
+       fnc_build_graphml(routers,edges,global_dict,router_mode,filename)\r
diff --git a/python-graph-topology/flujo.graphml b/python-graph-topology/flujo.graphml
new file mode 100644 (file)
index 0000000..b7572a6
--- /dev/null
@@ -0,0 +1,1051 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+  <!--Created by yEd 3.20-->
+  <key attr.name="Description" attr.type="string" for="graph" id="d0"/>
+  <key for="port" id="d1" yfiles.type="portgraphics"/>
+  <key for="port" id="d2" yfiles.type="portgeometry"/>
+  <key for="port" id="d3" yfiles.type="portuserdata"/>
+  <key attr.name="url" attr.type="string" for="node" id="d4"/>
+  <key attr.name="description" attr.type="string" for="node" id="d5"/>
+  <key for="node" id="d6" yfiles.type="nodegraphics"/>
+  <key for="graphml" id="d7" yfiles.type="resources"/>
+  <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+  <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+  <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+  <graph edgedefault="directed" id="G">
+    <data key="d0" xml:space="preserve"/>
+    <node id="n0">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.start2">
+          <y:Geometry height="40.0" width="80.0" x="129.49722222222223" y="0.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.94921875" x="24.025390625" xml:space="preserve" y="11.015625">start<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n1">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="119.8037688391608" x="109.59533780264184" y="70.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="100.7734375" x="9.515165669580398" xml:space="preserve" y="5.34375">db = mysqldb.connect()<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n2">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="177.19931904435913" x="80.89756270004267" y="124.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="170.77734375" x="3.2109876471795644" xml:space="preserve" y="5.34375">df_routers_list = pd.read_sql(query10,db)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n3">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="171.71488026853143" x="83.63978208795652" y="232.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="167.3125" x="2.2011901342657154" xml:space="preserve" y="5.34375">df_object_list = pd.concat(topos,routers)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n4">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.start2">
+          <y:Geometry height="40.0" width="80.0" x="129.49722222222223" y="2241.759668445763"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="36.625" x="21.6875" xml:space="preserve" y="11.015625">quit()<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n5">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="75.9763981141266" x="131.50902316515894" y="801.3125"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="69.09375" x="3.441324057063298" xml:space="preserve" y="5.34375">g0 = gv.Graph()<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n6">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.decision">
+          <y:Geometry height="40.0" width="75.97639811412657" x="131.50902316515896" y="718.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.2890625" x="10.343667807063298" xml:space="preserve" y="13.34375">router_mode</y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n7">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="19.61365784967421" width="65.62153080906506" x="136.6864568176897" y="855.3125"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.7734375" x="4.924046654532532" xml:space="preserve" y="3.1505789248370775">g0 attributes<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="-1.4432899320127035E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n8">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="86.33126541918818" x="126.33158951262814" y="988.2386578496742"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="78.28125" x="4.025007709594092" xml:space="preserve" y="5.34375">g0.node attributes<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n9">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="66.19899300699302" width="198.94454038498841" x="70.02495202972803" y="1096.2386578496742"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="59.875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="181.94921875" x="8.497660817494236" xml:space="preserve" y="3.161996503496539">router_name = router[0][0]
+router_function = get_attribute(HWfunction)
+router_int = get_attribute(Integrado)
+router_ckt_id = get_attribute(ckt_id)
+router_color = get_attribute(color)
+router_label = fnc_router_metadata(args[])<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="1.1102230246251565E-16" nodeRatioY="4.440892098500626E-16" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n10">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="19.613657849674098" width="70.80886456908345" x="134.0927899376805" y="1275.7501508566675"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.32421875" x="3.7423229095416843" xml:space="preserve" y="3.150578924836964">c = gv.Graph()<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="-2.220446049250313E-16" nodeRatioY="-4.3298697960381105E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n11">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="30.410653907682388" width="86.33126541918818" x="126.33158951262814" y="1325.3638087063418"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="72.51171875" x="6.909773334594092" xml:space="preserve" y="3.8928269538412223">c.body attributes
+c.node attributes<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="8.881784197001252E-16" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n12">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="177.19931904435913" x="80.89756270004267" y="178.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="160.01171875" x="8.593800147179564" xml:space="preserve" y="5.34375">df_topo_list = pd.read_sql(query11,db)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n13">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="171.71488026853143" x="83.63978208795652" y="286.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="166.10546875" x="2.8047057592657154" xml:space="preserve" y="5.34375">df_interfaces = pd.read_sql(query25,db)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n14">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.data">
+          <y:Geometry height="24.0" width="80.0" x="129.49722222222223" y="340.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.640625" x="10.1796875" xml:space="preserve" y="5.34375">getLoopbacks<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n15">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="171.71488026853143" x="83.63978208795652" y="394.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="145.69140625" x="13.011737009265715" xml:space="preserve" y="5.34375">df_conn = pd.read_sql(query20,db)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n16">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.data">
+          <y:Geometry height="24.0" width="121.3595035931414" x="108.81747042565154" y="448.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="84.88671875" x="18.2363924215707" xml:space="preserve" y="5.34375">arrangeConnections<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n17">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="24.0" width="171.71488026853143" x="83.63978208795652" y="502.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="165.3203125" x="3.1972838842657154" xml:space="preserve" y="5.34375">df_attributes = pd.read_sql(query15,db)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n18">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.data">
+          <y:Geometry height="24.0" width="121.3595035931414" x="108.81747042565154" y="556.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="75.0859375" x="23.1367830465707" xml:space="preserve" y="5.34375">arrangeAttributes<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n19">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.data">
+          <y:Geometry height="24.0" width="200.50027513896904" x="69.24708465273771" y="610.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="172.015625" x="14.242325069484522" xml:space="preserve" y="5.34375">global_dict = addAttrToDict(df_attributes)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n20">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="141.8037688391608" x="98.59533780264184" y="664.0"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="126.48046875" x="7.661650044580398" xml:space="preserve" y="0.6875">edges = fnc_edge_list(args[])
+routers = fnc_node_list(args[])<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n21">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.decision">
+          <y:Geometry height="40.0" width="70.80886456908345" x="134.0927899376805" y="904.9261578496742"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.2890625" x="7.759901034541713" xml:space="preserve" y="13.34375">router_mode</y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n22">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="97.4257661031827" x="242.6629105992023" y="988.2386578496742"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="78.1015625" x="9.662101801591348" xml:space="preserve" y="5.34375">g0.body attributes<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n23">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimit">
+          <y:Geometry height="24.0" width="104.40790150478796" x="117.29327146982826" y="1042.2386578496742"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="83.29296875" x="10.557466377393979" xml:space="preserve" y="5.34375">for router in routers<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n24">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.decision">
+          <y:Geometry height="40.0" width="70.80886456908345" x="134.0927899376805" y="1192.4376508566675"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.2890625" x="7.759901034541713" xml:space="preserve" y="13.34375">router_mode</y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n25">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimit">
+          <y:Geometry height="24.0" width="104.40790150478796" x="117.29327146982826" y="1391.9795601471217"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="70.921875" x="16.74301325239398" xml:space="preserve" y="5.34375">for port in router<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n26">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="36.410195066194945" width="86.33126541918818" x="126.33158951262814" y="1452.1846576802195"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="74.78515625" x="5.773054584594092" xml:space="preserve" y="2.236347533097387">node_id = port[1]
+c.node(node_id)
+port_workout<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="-2.3314683517128287E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n27">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="86.33126541918818" x="126.33158951262814" y="1572.5948527464147"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.0859375" x="10.622663959594092" xml:space="preserve" y="5.34375">g0.subgraph(c)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n28">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="19.613657849674098" width="70.80886456908345" x="377.66659946149" y="1275.7501508566675"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="53.88671875" x="8.461072909541713" xml:space="preserve" y="3.150578924836964">struct_name<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="-2.220446049250313E-16" nodeRatioY="-4.3298697960381105E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n29">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimit">
+          <y:Geometry height="24.0" width="104.40790150478796" x="360.8670809936377" y="1328.5691356601828"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="70.921875" x="16.743013252394007" xml:space="preserve" y="5.34375">for port in router<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="2.220446049250313E-16" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n30">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="36.410195066194945" width="111.85982355872306" x="357.1411199666702" y="1385.7744626140243"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="99.83984375" x="6.009989904361532" xml:space="preserve" y="2.236347533097387">node_id = port[1]
+node_string=fnc(args[])
+port_workout<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="-2.3314683517128287E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n31">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="196.43676596091183" x="314.85264876557585" y="1518.5948527464147"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="178.9296875" x="8.753539230455829" xml:space="preserve" y="5.34375">g0.body.append(struct_name+node_string)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="-1.6653345369377348E-16" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n32">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimit">
+          <y:Geometry height="24.0" width="86.33126541918818" x="126.33158951262814" y="1676.2085105960891"/>
+          <y:Fill color="#CCFFCC" color2="#CCFFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.01171875" x="13.659773334594092" xml:space="preserve" y="5.34375">for e in edges<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n33">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.decision">
+          <y:Geometry height="40.0" width="70.80886456908345" x="134.0927899376805" y="1730.2085105960891"/>
+          <y:Fill color="#CCFFCC" color2="#CCFFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.2890625" x="7.759901034541713" xml:space="preserve" y="13.34375">router_mode</y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n34">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="39.99999999999994" width="86.33126541918818" x="10.000240306278926" y="1818.1772605960891"/>
+          <y:Fill color="#CCFFCC" color2="#CCFFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="68.86328125" x="8.733992084594092" xml:space="preserve" y="4.03125">edgeA = e[0][0]
+edgeB = e[0][1]
+edge_workout<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="6.661338147750939E-16" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n35">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="39.99999999999994" width="86.33126541918818" x="126.33158951262814" y="1818.1772605960891"/>
+          <y:Fill color="#CCFFCC" color2="#CCFFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="68.86328125" x="8.733992084594092" xml:space="preserve" y="4.03125">edgeA = e[0][0]
+edgeB = e[0][1]
+edge_workout<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="6.661338147750939E-16" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n36">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="135.49805808676683" x="101.74819317883882" y="1888.1772605960891"/>
+          <y:Fill color="#CCFFCC" color2="#CCFFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="127.765625" x="3.866216543383416" xml:space="preserve" y="5.34375">g0.edge(edgeA, edgeB, args[])<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n37">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.decision">
+          <y:Geometry height="40.0" width="70.80886456908345" x="134.0927899376805" y="2045.790918445763"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.2890625" x="7.759901034541713" xml:space="preserve" y="13.34375">router_mode</y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n38">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="86.33126541918818" x="126.33158951262814" y="1991.7909184457633"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="49.5234375" x="18.403913959594092" xml:space="preserve" y="5.34375">g0.render()<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n39">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="141.8037688391608" x="98.59533780264184" y="2133.759668445763"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="126.48046875" x="7.661650044580398" xml:space="preserve" y="0.6875">edges = fnc_edge_list(args[])
+routers = fnc_node_list(args[])<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n40">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.process">
+          <y:Geometry height="23.999999999999943" width="230.70994230017317" x="54.14225107213565" y="2187.759668445763"/>
+          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="206.39453125" x="12.157705525086612" xml:space="preserve" y="5.34375">graphml(routers, edges, global_dict, router_mode)<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="1.1102230246251565E-16" nodeRatioY="1.2212453270876722E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n41">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimitEnd">
+          <y:Geometry height="19.613657849674155" width="80.0" x="129.49722222222223" y="1626.5948527464147"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="66.83984375" x="6.580078125" xml:space="preserve" y="3.150578924837191">end_for_routers<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="5.773159728050814E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n42">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimitEnd">
+          <y:Geometry height="19.613657849674155" width="80.0" x="129.49722222222223" y="1520.7880238215776"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="58.63671875" x="10.681640625" xml:space="preserve" y="3.150578924837191">end_for_ports<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="5.773159728050814E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n43">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimitEnd">
+          <y:Geometry height="19.613657849674155" width="80.0" x="373.07103174603174" y="1460.58292628848"/>
+          <y:Fill color="#FFCC99" color2="#FFCC99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="58.63671875" x="10.681640625" xml:space="preserve" y="3.150578924837191">end_for_ports<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="5.773159728050814E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <node id="n44">
+      <data key="d6">
+        <y:GenericNode configuration="com.yworks.flowchart.loopLimitEnd">
+          <y:Geometry height="19.613657849674155" width="80.0" x="129.49722222222223" y="1942.1772605960891"/>
+          <y:Fill color="#CCFFCC" color2="#CCFFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="13.3125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="62.23828125" x="8.880859375" xml:space="preserve" y="3.150578924837191">end_for_edges<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="5.773159728050814E-15" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
+        </y:GenericNode>
+      </data>
+    </node>
+    <edge id="e0" source="n0" target="n1">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="20.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e1" source="n1" target="n2">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e2" source="n2" target="n12">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e3" source="n6" target="n5">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="20.0" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="38.23046875" x="-19.115235053168362" xml:space="preserve" y="15.0">[0,1,2,3]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e4" source="n5" target="n7">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-9.806828924837106"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e5" source="n7" target="n21">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837106" tx="0.0" ty="-20.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e6" source="n10" target="n11">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837049" tx="0.0" ty="-15.205326953841194"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e7" source="n12" target="n3">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e8" source="n3" target="n13">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e9" source="n13" target="n14">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e10" source="n14" target="n15">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e11" source="n15" target="n16">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e12" source="n16" target="n17">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e13" source="n17" target="n18">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e14" source="n18" target="n19">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e15" source="n19" target="n20">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e16" source="n21" target="n8">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="20.0" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="15.33203125" x="-7.666016303168419" xml:space="preserve" y="15.000010388736655">[0]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e17" source="n21" target="n22">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="35.40443228454173" sy="0.0" tx="0.0" ty="-11.999999999999972">
+            <y:Point x="291.37579365079364" y="924.9261578496742"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="30.59765625" x="32.50073884928662" xml:space="preserve" y="-6.656239611263345">[1,2,3]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e18" source="n8" target="n23">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e19" source="n22" target="n23">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="52.20395075239398" ty="0.0">
+            <y:Point x="291.37579365079364" y="1054.2386578496742"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e20" source="n23" target="n9">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-33.09949650349651"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e21" source="n9" target="n24">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="33.09949650349651" tx="0.0" ty="-20.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e22" source="n24" target="n10">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="20.0" tx="0.0" ty="-9.806828924837049"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="15.33203125" x="-7.666016303168419" xml:space="preserve" y="15.00002878635496">[0]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e23" source="n11" target="n25">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="15.205326953841194" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e24" source="n25" target="n26">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-18.205097533097472"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e25" source="n42" target="n27">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837077" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e26" source="n41" target="n32">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837077" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e27" source="n24" target="n28">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="35.40443228454173" sy="0.0" tx="0.0" ty="-9.806828924837049">
+            <y:Point x="413.07103174603174" y="1212.4376508566675"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="30.59765625" x="93.34835789690567" xml:space="preserve" y="-6.65622121364504">[1,2,3]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e28" source="n29" target="n30">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-18.205097533097472"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e29" source="n28" target="n29">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837049" tx="0.0" ty="-12.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e30" source="n41" target="n23">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="-40.0" sy="0.0" tx="-52.20395075239398" ty="0.0">
+            <y:Point x="55.02460317460317" y="1636.401681671252"/>
+            <y:Point x="55.02460317460317" y="1054.2386578496742"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e31" source="n32" target="n33">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="0.0" ty="-20.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e32" source="n33" target="n34">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="-35.40443228454173" sy="0.0" tx="0.0" ty="-19.99999999999997">
+            <y:Point x="53.16587301587302" y="1750.2085105960891"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="15.33203125" x="-52.69197284451231" xml:space="preserve" y="-6.656235497660873">[0]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e33" source="n33" target="n35">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="20.0" tx="0.0" ty="-19.99999999999997"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="30.59765625" x="-15.29882880316842" xml:space="preserve" y="17.328139502339127">[1,2,3]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e34" source="n35" target="n36">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="19.99999999999997" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e35" source="n34" target="n36">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="19.99999999999997" tx="-67.74902904338342" ty="0.0">
+            <y:Point x="53.16587301587302" y="1900.1772605960891"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e36" source="n44" target="n32">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="40.0" sy="0.0" tx="43.16563270959409" ty="0.0">
+            <y:Point x="299.85238095238094" y="1951.9840895209263"/>
+            <y:Point x="299.85238095238094" y="1688.2085105960891"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e37" source="n38" target="n37">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-20.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e38" source="n20" target="n6">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-20.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e39" source="n37" target="n39">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="20.0" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="8" fontStyle="plain" height="13.3125" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="30.59765625" x="-15.29882880316842" xml:space="preserve" y="17.281396961388054">[1,2,3]<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e40" source="n39" target="n40">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e41" source="n40" target="n4">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-20.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e42" source="n37" target="n4">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="35.40443228454171" sy="0.0" tx="19.96875" ty="0.0">
+            <y:Point x="299.85238095238094" y="2065.790918445763"/>
+            <y:Point x="299.85238095238094" y="2261.759668445763"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e43" source="n27" target="n41">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-9.806828924837077"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e44" source="n31" target="n41">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="12.0" tx="40.0" ty="0.0">
+            <y:Point x="413.07103174603174" y="1636.401681671252"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e45" source="n26" target="n42">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="18.205097533097472" tx="0.0" ty="-9.806828924837077"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e46" source="n42" target="n25">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="40.0" sy="0.0" tx="52.20395075239398" ty="0.0">
+            <y:Point x="299.85238095238094" y="1530.5948527464147"/>
+            <y:Point x="299.85238095238094" y="1403.9795601471217"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e47" source="n43" target="n31">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837077" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e48" source="n30" target="n43">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="18.205097533097472" tx="0.0" ty="-9.806828924837077"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e49" source="n43" target="n29">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="40.0" sy="0.0" tx="52.20395075239401" ty="0.0">
+            <y:Point x="484.00119047619046" y="1470.3897552133171"/>
+            <y:Point x="484.00119047619046" y="1340.5691356601828"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e50" source="n36" target="n44">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="11.999999999999972" tx="0.0" ty="-9.806828924837077"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e51" source="n44" target="n38">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="9.806828924837077" tx="0.0" ty="-11.999999999999972"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+  </graph>
+  <data key="d7">
+    <y:Resources/>
+  </data>
+</graphml>
diff --git a/python-graph-topology/functions.py b/python-graph-topology/functions.py
new file mode 100644 (file)
index 0000000..7e69161
--- /dev/null
@@ -0,0 +1,694 @@
+########################################################################
+# Functions
+########################################################################
+
+from operator import itemgetter
+from itertools import groupby
+import re
+import datetime
+import networkx as nx
+import pandas as pd 
+import pyyed
+
+# This function converts M,G,T capacity into Kbps
+# If no unit, return -1
+# If problems, return 0
+def fnc_aux_convert_speed(capacity, outUnit=None):
+
+       dictUnit = {'K':1E3, 'M':1E6, 'G':1E9, 'T':1E12}
+
+       if capacity == 'vPort':
+               unit  = "G"
+               value = 20
+       else:
+               unit  = str(capacity[-1:])
+               value = int(capacity[:-1])
+       
+
+       if outUnit not in dictUnit.keys() or unit not in dictUnit.keys():
+               return 0
+       else:
+               value = value*dictUnit[unit] / dictUnit[outUnit]
+
+       return value
+
+def get_attribute(key, attribute, global_dict):
+  try:
+    return global_dict[key][attribute]
+  except:
+    return "N/A"
+
+def setFinalValue(row):
+       
+       rtrName          = row['name']
+       attrName     = row['attrName'].replace(" ","")
+       dict_value   = row['dict_value']
+       string_value = row['string_value']
+       finalValue   = 'N/A'
+
+       if attrName in ['Integrado','HWtype','Sync_Ref_Order','HWfunction','Int_Type']:
+               finalValue = dict_value
+       elif attrName in ['Sync_Ref1','Sync_Ref2',]:
+               finalValue = string_value
+       else:
+               finalValue = "N/A"
+       row['finalValue'] = finalValue
+       
+       return row
+
+def fnc_chains_ring(vector):
+       topoString = ""
+       tempList   = []
+       len_vector = len(vector)
+       i=1
+
+       regexp = {
+           'Anillo':        re.compile(r'^(\w{5})_(\d{3})$'),
+           'Anillo_TX':     re.compile(r'^(\w{5})_(\d{3})_(\D{1,6})$'),
+           'Cadena':        re.compile(r'^(\w{5}_\w{5})_(\d{3})$'),
+           'Cadena_Radial': re.compile(r'^(\w{5}_\w{5})_(\D{1,6})$'),
+           'Cadena_TX':     re.compile(r'^(\w{5}_\w{5})_(\d{3})_(\D{1,6})$'),
+           'Area':          re.compile(r'^(0.0.\d{1}.\d{1,2})$'),
+           'Region':        re.compile(r'(.*0.0.\d{1}.\d{1,2}.+)'),
+           # ...
+       }
+
+       # We can have many topos inside vector
+       for topo in vector:
+
+               for key, pattern in regexp.items():
+                       match = pattern.match(topo)
+                       if match:
+                               name   = match.groups()[0]
+                               tot    = match.group()
+                               tempList.append( (key, name, tot) )
+
+       return tempList
+
+
+# Function that builds the filename
+def fnc_build_filename(vector):
+       info = fnc_chains_ring(vector)
+       len_vector= len(vector)
+
+       #print info
+
+       if len_vector == 1:
+
+               tipoTopo  = info[0][0]
+               agregador = info[0][1]
+               topologia = info[0][2]
+
+               topoName1 = "Topologia "
+               topoName2 = tipoTopo
+               topoName3 = " - MR LR - "
+               topoName4 = topologia
+               filename  = "pix/topo/" + agregador + "/" + topoName1 + topoName2 + topoName3 + topoName4
+
+       elif len_vector >1:
+
+               tipoTopo  = "-".join(list(set([name[0] for name in info])))
+               agregador = "-".join(list(set([name[1] for name in info])))
+               topologia = "-".join(list(set([name[2] for name in info])))
+
+               topoName1 = "Topologia "
+               topoName2 = tipoTopo
+               topoName3 = " - MR LR - "
+               topoName4 = topologia
+               filename  = "pix/topo/" + agregador + "/" + topoName1 + topoName2 + topoName3 + topoName4
+
+       #filename=filename + "_" + version_script + "_" +now.strftime("%Y-%m-%d")+".dot"
+       return filename + ".dot"
+
+
+# Function that returns whether we have a input_string or router_name
+def fnc_input_string_type(vector):
+
+       listTopo   = []
+       listRouter = []
+
+       for name in vector:
+               if name[:2] == 'R:':
+                       listRouter.append(name[2:])
+               else:
+                       listTopo.append(name)
+
+       return(listTopo,listRouter)
+
+
+
+# Funcion que organiza los puertos de cada nodo
+def fnc_port_list(routers):
+       router_list=[]
+       port_list=[]
+       for router in routers:
+               #print router[0]
+               router_id = router[0][0]
+               for port in router:
+                       port_list.append(port[1])
+               router_list.append((router_id,port_list))
+               port_list=[]
+
+       return router_list
+
+# Function that returns de speed of the port
+def fnc_port_speed(port_string):
+
+       speed = port_string.split('B')[0]
+       
+       speedDict = {
+               "100"  :"100Mb",
+               "1000" :"1G",
+               "10G"  :"10G",
+               "100G" :"100G",
+
+               "SFP-CES" :"n/ETH",
+               "SFP-ATM" :"n/ETH",
+               "SFP-ASAP":"n/ETH",
+               
+               "empty SFP-1000":"n/SFP",
+               "virtual port"  :"vPort",               
+       }
+
+       return speedDict.get(speed,"N/A")
+
+# Function to compare speeds for egressRate in vPorts
+def fnc_speed_compare(strSpeed):
+
+       print strSpeed
+
+       speed = strSpeed.split(":")[0]
+       unit  = speed[-1:]
+       value = float(speed[:-1])
+       if unit == "G":
+               return value
+       elif unit == "M":
+               return float(value/1000)
+
+# Function that returns the SFP type
+def fnc_port_sfp(port_string):
+
+       if port_string == "virtual port":
+               return "LAG"
+       elif port_string == "spoke-sdp":
+               return "VLL"
+       elif port_string == "SFP-CES" or port_string == "SFP-ATM" or port_string == "SFP-ASAP":
+               return port_string.split('-')[1]
+       else:
+               sfp_type = port_string.split('-')
+               sfp_type = sfp_type[1]
+               return sfp_type
+
+# Function that creates a dictionary with global attributes
+def fnc_add_atributes_to_dic_global(df):
+       #                   name HWfunction            HWtype Integrado Sync_Ref1 Sync_Ref2      Sync_Ref_Order
+       # 0     C1026_SF270_SARX        NaN    ALU%GPASS%SARX        si     1/2/6     1/3/6  ref1 ref2 external
+       # 1     C1406_ND270_SARX        NaN    ALU%GPASS%SARX        si     1/3/7     1/2/7  ref2 ref1 external
+       # 2     C1708_ND470_SARX        NaN    ALU%GPASS%SARX        si     1/2/7     1/3/6  ref2 ref1 external
+       # 3     C2155_SND70_SARA        NaN    ALU%GPASS%SARA        si     1/1/5     1/1/6  ref1 ref2 external
+       # 4     C3110_CTG70_SARM        NaN    ALU%GPASS%SARM       NaN     1/1/2     1/1/1  ref1 ref2 external
+       # 5    CF145_TGR70_SAR28        NaN   ALU%GPASS%SAR28        no     1/1/5     1/1/4  ref1 ref2 external
+       # 6     CF145_TGR70_SAR8        NaN    ALU%GPASS%SAR8        si       NaN       NaN                 NaN
+       # 7     CF181_R2770_SARA        NaN    ALU%GPASS%SARA        si     1/1/5     1/1/6  ref1 ref2 external
+       # 8     CF352_GR270_SARX        NaN    ALU%GPASS%SARX        si     1/3/7     1/2/6  ref1 ref2 external
+       # 9   CFR17_TOT70_IXR-R6    Mid-Ran  ALU%GPASS%IXR-R6        si     3/1/1     3/2/1  ref1 ref2 bits ptp
+       # 10  CFR17_TOT71_IXR-R6    Mid-Ran  ALU%GPASS%IXR-R6        si     3/2/1     3/1/1  ref1 ref2 bits ptp
+       # 11   TC3067_HMT70_SARX        NaN    ALU%GPASS%SARX        si     1/2/6     1/3/6  ref1 ref2 external
+
+       dict_global = {}
+
+       if 'HWfunction' not in df.columns:
+               df['HWfunction'] = "N/A"
+
+       if 'HWtype' not in df.columns:
+               df['HWtype'] = "N/A"
+
+       if 'Sync_Ref1' not in df.columns:
+               df['Sync_Ref1'] = "N/A"
+
+       if 'Sync_Ref2' not in df.columns:
+               df['Sync_Ref2'] = "N/A"
+
+       if 'Sync_Ref_Order' not in df.columns:
+               df['Sync_Ref_Order'] = "N/A"
+
+       if 'Integrado' not in df.columns:
+               df['Integrado'] = "N/A"
+
+       if "Int_Type" not in df.columns:
+               df['Int_Type'] = "N/A"
+
+       #print df
+
+       for attrib in df.itertuples():
+
+               router_name    = attrib.name
+               HWfunction     = attrib.HWfunction
+               HWtype         = attrib.HWtype
+
+               if HWtype != "N/A":
+                       try:
+                               HWtype = attrib.HWtype.split("%")[2]
+                       except:
+                               try:
+                                       HWtype = router_name.split("_")[2]
+                               except:
+                                       HWtype = "N/A"
+
+               Integrado      = attrib.Integrado
+               Sync_Ref1      = attrib.Sync_Ref1
+               Sync_Ref2      = attrib.Sync_Ref2
+               Sync_Ref_Order = attrib.Sync_Ref_Order
+               system         = attrib.ip
+               Int_Type       = attrib.Int_Type
+
+               dict_global[router_name] = {}
+               dict_global[router_name]['system']         = system
+               dict_global[router_name]['HWfunction']     = HWfunction
+               dict_global[router_name]['Integrado']      = Integrado
+               dict_global[router_name]['Sync_Ref1']      = Sync_Ref1
+               dict_global[router_name]['Sync_Ref2']      = Sync_Ref2
+               dict_global[router_name]['Sync_Ref_Order'] = Sync_Ref_Order
+               dict_global[router_name]['Int_Type']       = Int_Type 
+               dict_global[router_name]['color']          = fnc_router_color(HWfunction, Integrado, Int_Type)
+               dict_global[router_name]['HWtype']         = HWtype
+               dict_global[router_name]['weight']         = fnc_router_weight(HWtype)
+
+               if Sync_Ref1: 
+                       dict_global[router_name][Sync_Ref1] = 'Sync_Ref1'
+               if Sync_Ref2:
+                       dict_global[router_name][Sync_Ref2] = 'Sync_Ref2'
+
+       return dict_global
+
+# Function that creates a list which holds each router and all its ports.
+# Input: object_connections
+# [('Router1', '1/1/1'), ('Router1', '1/1/2')]
+# Output
+# ('Router1/1/1', {'label': '1/1/1'})
+# The output of this function is used as input to graphviz
+def fnc_node_list(df, global_dict, router_mode, graph_hp, graph_lag, graph_cpam):
+
+       temp_list=[]
+
+       subset = df[['name1','port1','name2','port2','cable','port1Speed','port2Speed','ip_x','ip_y']]
+
+       for row in subset.itertuples():
+
+               cableID = row.cable
+               if not cableID: cableID = ""
+
+               if ("LAG" in cableID.upper() and graph_lag=="n") or ("HAIRPIN" in cableID.upper() and graph_hp=="n") or ("CPAM" in cableID.upper() and graph_cpam=="n"):
+                       pass 
+               else:
+
+                       routerA    = row.name1
+                       portA      = row.port1
+                       portAspeed = fnc_port_speed(row.port1Speed)
+                       portAtype  = fnc_port_sfp(row.port1Speed)
+                       ipA        = row.ip_x
+                       if not ipA:     ipA="N/A"
+                       nodeA      = routerA + "_" + portA
+                       ref1a      = get_attribute(routerA,portA,global_dict)
+
+                       routerB    = row.name2
+                       portB      = row.port2
+                       portBspeed = fnc_port_speed(row.port2Speed)
+                       portBtype  = fnc_port_sfp(row.port2Speed)
+                       ipB        = row.ip_y
+                       if not ipB: ipB="N/A"
+                       nodeB      = routerB + "_" + portB
+                       ref1b      = get_attribute(routerB,portB,global_dict)
+
+                       if router_mode == "0":
+                               labelA="<"+ portA + "<BR />" + portAtype + "-" +  portAspeed + "<BR />" + ipA + "<BR />" + ref1a +">"
+                               labelB="<"+ portB + "<BR />" + portBtype + "-" +  portBspeed + "<BR />" + ipB + "<BR />" + ref1b +">"
+                       elif router_mode in ["1","2"]:
+                               labelA= portA + "&#92;n" + portAtype + "-" + portAspeed + "&#92;n" + ipA + "&#92;n" + ref1a
+                               labelB= portB + "&#92;n" + portBtype + "-" + portBspeed + "&#92;n" + ipB + "&#92;n" + ref1b
+                       elif router_mode in ["3","4"]:
+                               labelA=""
+                               labelB=""
+
+                       temp_list.append((routerA,nodeA,{'label':labelA}))
+                       temp_list.append((routerB,nodeB,{'label':labelB}))
+
+       # List will be ordered and sorted always by the first field
+       # which is the router name
+       if router_mode in ['0','1','2','3']:
+               lista_sorted  = sorted(temp_list, key=itemgetter(0))
+               lista_grouped = groupby(lista_sorted, key=itemgetter(0))
+
+               a = []
+               for i,rou in enumerate(lista_grouped):
+                       a.append(list(rou[1]))
+
+               return a
+
+       elif router_mode in ['4']:
+               return temp_list
+
+# Function that builds a list which holds the connections among routers.
+# The output of this function is used as input to graphviz
+def fnc_edge_list(df, graph_lag, graph_hp, graph_cpam, router_mode):
+
+       subset = df[['name1','port1','name2','port2','cable','port1Speed','port2Speed','intName1','intName2']]
+
+       edge_list=[]
+
+       for row in subset.itertuples():
+               
+               routerA    = row.name1
+               portA      = row.port1
+               routerB    = row.name2
+               portB      = row.port2
+               cableID    = row.cable
+               portAspeed = fnc_port_speed(row.port1Speed)
+               portBspeed = fnc_port_speed(row.port2Speed)
+               intName1   = row.intName1
+               intName2   = row.intName2
+
+               nodeA = routerA + "_" + portA
+               nodeB = routerB + "_" + portB
+
+               if not cableID or cableID == "N/A": cableID = ""
+
+               if ("LAG" in cableID.upper() and graph_lag=="n") or ("HAIRPIN" in cableID.upper() and graph_hp=="n") or ("CPAM" in cableID.upper() and graph_cpam=="n"):
+                       pass
+               else:
+                       if router_mode in ['0','1','2','3']:
+                               edge_list.append( ( (nodeA,nodeB),{'label':cableID},(portAspeed,portBspeed),(intName1,intName2) ) )
+                       elif router_mode in ['4']:
+                               edge_list.append( (routerA,routerB,cableID) )
+
+       return edge_list
+
+# Function to obtain topology name
+def fnc_build_topo_name(vector):
+       topo_name=""
+       len_vector= len(vector)
+       i=1
+       for tn in vector:
+               if i < len_vector:
+                       topo_name=topo_name+tn+"-"
+               else:
+                       topo_name=topo_name+tn
+               i=i+1
+
+       return topo_name
+
+def fnc_router_weight(HWtype):
+
+       if HWtype in ['SR12','SR12e','SR7','SRa8','SRa4']:
+               return 30
+       elif HWtype in ['IXR-R6']:
+               return 15
+       else:
+               return 1
+
+# Function that returns the color of the router depending on its
+# situation
+def fnc_router_color(HWfunction, intStatus, Int_Type):
+
+       # Color depending on function
+       functionDict = {
+               'High-Ran':             {'yEd':'#3399ff','graphviz':'lightblue4'},
+               'High-Ran-ABR': {'yEd':'#3399ff','graphviz':'lightblue4'},
+               'Mid-Ran':              {'yEd':'#ff99cc','graphviz':'lightpink4'},
+               'AggEthernet':  {'yEd':'#33ff33','graphviz':'limegreen'},
+               'FronteraPE':   {'yEd':'#cccc00','graphviz':'darkgoldenrod'},
+               'TX':                   {'yEd':'#ffff00','graphviz':'yellow'},
+       }
+
+       intStatusDict = {
+               'no':{'yEd':'#ffcc00','graphviz':'orange'},
+       }
+
+       intTypeDict = {
+               'swap':                         {'yEd':'#66ccff','graphviz':'lightblue2'},
+               'cambioArea':           {'yEd':'#808000','graphviz':'khaki'},
+               'integracion':          {'yEd':'#99ccff','graphviz':'lightblue3'},
+               'cambioTopologia':      {'yEd':'#ccffff','graphviz':'lightblue1'},
+               'reinsercion':          {'yEd':'#ff6600','graphviz':'red'},
+       }
+
+       refOrderDict = {
+               'ref1 ref2':{'yEd':'#99ccff','graphviz':'lightblue3'},
+               'ref2 ref1':{'yEd':'#ccffff','graphviz':'lightblue1'}
+       }
+
+       color = {'yEd':'#c0c0c0','graphviz':'grey'}
+
+       ####
+
+       if intStatus == 'no':
+               color = intStatusDict.get(intStatus,color)
+
+       elif intStatus == 'si':
+
+               if HWfunction != "N/A":
+                       color = functionDict.get(HWfunction,color)
+               else:
+                       if Int_Type != "N/A":
+                               color = intTypeDict.get(Int_Type,color)
+       
+       return color
+
+
+# Function to process label of edges
+def fnc_edge_format(labelText, what, portSpeed):
+       
+       # LAG3:1G:DWDM:10172
+       # 10G:-1:DWDM:10265
+       # 296M:-1:MW
+       # 3G:-1:2
+
+       stringLen = len(labelText.split(":"))
+       portSpeed = portSpeed[0]
+
+       if portSpeed[:3] != "LAG":
+
+               if  stringLen == 4:
+
+                       egressRate  = labelText.split(":")[0]
+                       metOspef        = labelText.split(":")[1]
+                       TxType          = labelText.split(":")[2]
+                       txTypeCkt       = labelText.split(":")[3]
+
+               elif stringLen == 3:
+
+                       egressRate  = labelText.split(":")[0]
+                       metOspef        = labelText.split(":")[1]
+                       TxType          = labelText.split(":")[2]
+                       txTypeCkt       = "NA"
+
+               elif stringLen == 2:
+
+                       egressRate  = labelText.split(":")[0]
+                       metOspef        = labelText.split(":")[1]
+                       TxType          = "FO"
+                       txTypeCkt       = "NA"
+
+               elif stringLen == 1:
+
+                       egressRate  = portSpeed
+                       metOspef        = "-1"
+                       TxType          = "FO"
+                       txTypeCkt       = "NA"
+
+               else:
+
+                       egressRate  = "1G"
+                       metOspef        = "-1"
+                       TxType          = "FO"
+                       txTypeCkt       = "NA"
+
+       colorDict = {
+               "CWDM" :"red",
+               "DWDM" :"blue",
+               "FO"   :"black",
+               "SDH"  :"green",
+               "MW"   :"pink",
+               "ARSAT":"navy",
+               "DATCO":"purple",
+       }
+
+       widthDict = {
+               0.1     :"0.5",
+               1       :"1.0",
+               10      :"2.5",
+               50      :"5.0",
+               100     :"10.0",
+       }
+
+       egressRate = int(fnc_aux_convert_speed(egressRate,'G'))
+       egressRate = min([x for x in widthDict.keys() if egressRate <= x])
+
+       if what == "color":
+               return colorDict.get(TxType,'yellow')
+       elif what == "width":
+               return widthDict.get(egressRate, '50.0')
+
+# Function that returns metadata of the router
+def fnc_router_metadata(global_dict, router_name, what, router_function, router_ckt_id, router_mode):
+
+       router_sync_order  = get_attribute(router_name, "Sync_Ref_Order", global_dict)
+       router_ip          = get_attribute(router_name, "system", global_dict)
+
+       if "TX" in router_function:
+
+               if what=="labelHtml":
+
+                       router_label=(
+                               "<"+
+                               "<font point-size=\"10\">"+router_ckt_id+"</font>"+"<BR />"
+                               +">"
+                               )
+                       return router_label
+
+               elif what=="labelText":
+
+                       router_label = router_ckt_id
+                       return router_label
+
+       else:
+
+               if what=="labelHtml":
+
+                       if router_mode == "3":
+                               router_label=(
+                                       "<"+
+                                       "<font point-size=\"10\">"+router_name+"</font>"+"<BR />"+
+                                       "<font point-size=\"9\">" +router_ip+"</font>"+"<BR />"
+                                       +">"
+                                       )
+                               return router_label
+
+                       else:
+                               router_label=(
+                                       "<"+
+                                       "<font point-size=\"10\">"+router_name+"</font>"+"<BR />"+
+                                       "<font point-size=\"9\">" +router_ip+"</font>"+"<BR />"+
+                                       "<font point-size=\"9\">" +router_sync_order+"</font>"
+                                       +">"
+                                       )
+                               return router_label
+
+               elif what=="labelText":
+
+                       if router_mode=="3":
+                               router_label = router_name + "&#92;n" + router_ip
+                               return router_label
+                       else:
+                               router_label = router_name + "&#92;n" + router_ip + "&#92;n" + router_sync_order
+                               return router_label
+
+# Function that returns port_string when router as a node
+def fnc_port_string(router_label, port_string, color, router_mode, router_function):
+
+       port_string=port_string[1:]
+       temp_port = port_string.split("|")
+
+       if "TX" in router_function:
+
+               if router_function == "TX_MIX":
+
+                       temp_string=""
+
+                       for port in port_string.split("|"):
+                               temp_string = temp_string + port.split("\n")[0] + "|"
+
+                       port_string = temp_string[:-1]
+
+                       temp_string = "{" + port_string + "}"
+                       temp_string = " [" + color + ",label=\"" + temp_string + "\"]"
+                       return temp_string
+
+               elif router_function == "TX_ARSAT":
+
+                       #print router_label
+
+                       temp_string = "{" + router_label + "}"
+                       temp_string = " [" + color + ",label=\"" + temp_string + "\"]"
+                       return temp_string
+
+       else:
+
+               if router_mode=="1":
+                       temp_string = "{" + router_label + "|" + port_string + "}"
+               elif router_mode=="2":
+                       temp_string = "{" + router_label + "|" + "{" + port_string + "}" + "}"
+               elif router_mode=="3":
+                       temp_string = router_label
+
+               temp_string = " [" + color + ",label=\"" + temp_string + "\"]"
+               return temp_string
+
+
+def fnc_build_graphml(routers,edges,global_dict,router_mode,filename):
+
+       if router_mode in ['1','2','3','4']:
+
+               G = pyyed.Graph()
+
+               nodes = pd.DataFrame(routers)
+
+               nodes.columns=['router_name','port','label']
+               nodes = nodes[['router_name']]
+               nodes = nodes.drop_duplicates()
+
+               links = pd.DataFrame(edges)
+               links.columns=['routerA','routerB','cableID']           
+
+               for router in nodes.itertuples():
+                       router_name     = router.router_name
+                       router_function = get_attribute(router_name,"HWfunction",global_dict)
+                       router_int      = get_attribute(router_name,"Integrado",global_dict)
+                       router_ckt_id   = get_attribute(router_name,"ckt_id",global_dict)
+                       router_color    = get_attribute(router_name,"color",global_dict)['yEd']
+                       router_label    = fnc_router_metadata(global_dict, router_name, 'labelHtml', router_function, router_ckt_id, router_mode)
+                       router_system   = get_attribute(router_name,"system",global_dict)
+
+                       G.add_node(router_name,label=router_name + "\n" + router_system, shape_fill=router_color)
+
+               for link in links.itertuples():
+                       edgeLabel = link.cableID
+                       G.add_edge(link.routerA,link.routerB, arrowhead='none',arrowfoot='none',label=edgeLabel)
+
+               G.write_graph(filename+'.graphml')                      
+
+
+       elif router_mode in ['0']:
+
+               G = pyyed.Graph()
+               
+               for router in routers:
+
+                       # Variables
+                       router_name     = router[0][0]
+                       router_function = get_attribute(router_name,"HWfunction",global_dict)
+                       router_int      = get_attribute(router_name,"Integrado",global_dict)
+                       router_ckt_id   = get_attribute(router_name,"ckt_id",global_dict)
+                       router_color    = get_attribute(router_name,"color",global_dict)['yEd']
+                       router_label    = fnc_router_metadata(global_dict, router_name, 'labelHtml', router_function, router_ckt_id, router_mode)
+                       router_system   = get_attribute(router_name,"system",global_dict)
+
+                       grupo = G.add_group(router_name,label=router_name + "\n" + router_system, fill=router_color)
+
+                       for port in router:
+                               node_id = port[1]
+                               port_id = port[2]['label']
+                               port_id = port_id.replace('<BR />','\n')
+                               port_id = port_id.replace('<','')
+                               port_id = port_id.replace('>','')
+                               grupo.add_node(node_id, label=port_id)
+
+               for e in edges:
+
+                       edgeA     = e[0][0]
+                       edgeB     = e[0][1]
+                       edgeLabel = e[1]['label']
+
+                       G.add_edge(edgeA,edgeB, arrowhead='none',arrowfoot='none',label=edgeLabel)
+
+               G.write_graph(filename+'.graphml')
index 14fb994325914baf0d63720a86944dbb89477f41..23e8ee171c382f80d09e544437f850d25e194c32 100644 (file)
@@ -4,12 +4,13 @@
 // =====================================
 //
 // Author: Lucas Scola
-// e-mail: lucas.scola@hotmail.com.ar
+// e-mail: ucas.scola@hotmail.com.ar
 //
 // Version: 1.0
 //
 // =====================================
 // Changelog:
+// *1.2: Legend added
 // *1.1: -Goodbye inline style.
 //                      -New inputs implementation.
 // *1.0: First implementation.
 
        array_push($indexlayout, array('graphtopo'));
        addCSS('css/gstyle.css');
+       addJS('js/jquery-image.js');
+       /* addCSS('css/jquery.ui.resizable.css');
+       addJS('js/jquery.ui.core.js');
+       addJS('js/jquery.ui.widget.js');
+       addJS('js/jquery.ui.mouse.js');
+       addJS('js/jquery.ui.resizable.js');
+        */
 
-       $page['graphtopo']['title'] = 'Topology';
+       $page['graphtopo']['title']  = 'Topology';
        $page['graphtopo']['parent'] = 'index';
 
        $tab['graphtopo']['default'] = 'View';
        registerTabHandler ('graphtopo', 'default', 'renderGraphTopo');
 
-       $image['graphtopo']['path'] = 'pix/logo.png';
-       $image['graphtopo']['width'] = 218;
+       $image['graphtopo']['path']   = 'pix/logo.png';
+       $image['graphtopo']['width']  = 218;
        $image['graphtopo']['height'] = 200;
 
        function renderGraphTopo()
        {
                //variables intialization:
                $topo = $router_mode = $format = "";
-               $algo = $rankdir = $lines = $aggr = "";
+               $algo = $rankdir = $lines = $aggr = $lag = "";
+               $nodesep = $ranksep = "";
                $svgName = "";
                $exitCode= -2;
                $scriptOutput = array();
                //check if it's a POST method:
                if ($_SERVER["REQUEST_METHOD"] == "POST") {
                        //take the arguments from HTML form:
-                       $topo = $_POST["topo"];
-                       $router_mode = $_POST["router_mode"];
-                       $format = $_POST["format"];
-                       $algo = $_POST["algo"];
-                       $rankdir = $_POST["rankdir"];
-                       $lines = $_POST["lines"];
-                       $aggr = $_POST["aggr"];
+                       $topo                   = $_POST["topo"];
+                       $router_mode    = $_POST["router_mode"];
+                       $format                 = $_POST["format"];
+                       $algo                   = $_POST["algo"];
+                       $rankdir                = $_POST["rankdir"];
+                       $lines                  = $_POST["lines"];
+                       $aggr                   = $_POST["aggr"];
+                       $lag                    = $_POST["lag"];
+                       $nodesep                = $_POST["nodesep"];
+                       $ranksep                = $_POST["ranksep"];
                }
                ?>
+               <!-- Page help -->
+               <!--
+               <div class="help">
+                       <div id="help-button">
+                               <h2 id='help-msg'>Help</h2>
+                       </div>
+                       <div id="help-pane">
+                               <img id="help-img" src="pix/legend_topo.png">
+                               <!-- <div id="help-img"></div> -->
+                       </div>
+               </div>
+               -->
+
                <div class="settings">
                                        <!-- HTML menu formatting -->
                                        <div class="parameters">
                                                        <input type="submit" value="Execute">
                                                  </div>
                                                </fieldset>
-
                                                <fieldset class="fields">
+
                                                        <!-- Fields for customizing output -->
                                                        <legend>Advanced:</legend>
+
                                                        <div class="gdiv">
                                                        <label class="ginput" for="router_mode">Router mode:</label>
                                                        <select class="ginput" name="router_mode">
                                                                <option <?php if ($router_mode == "0") {?>selected="true" <?php }; ?>value="0">Router as cluster</option>
-                                                               <option <?php if ($router_mode == "1" || $router_mode == "") {?>selected="true" <?php }; ?>value="1">Router as node, one-row</option>
-                                                               <option <?php if ($router_mode == "2") {?>selected="true" <?php }; ?>value="2">Router as node, two-row</option>
+                                                               <option <?php if ($router_mode == "1" || $router_mode == "") {?>selected="true" <?php }; ?>value="1">Router as node, one-line</option>
+                                                               <option <?php if ($router_mode == "2") {?>selected="true" <?php }; ?>value="2">Router as node, two-line</option>
                                                                <option <?php if ($router_mode == "3") {?>selected="true" <?php }; ?>value="3">Router as node, only with name</option>
                                                        </select>
                                                        </div>
+
                                                        <div class="gdiv">
                                                        <label class="ginput" for="format">Format:</label>
                                                        <select class="ginput" name="format">
                                                                <option <?php if ($format == "1" || $format == "") {?>selected="true" <?php }; ?>value="1">SVG</option>
                                                        </select>
                                                        </div>
+
                                                        <div class="gdiv">
                                                        <label class="ginput" for="algo">Algorithm:</label>
                                                        <select class="ginput" name="algo">
                                                                <option <?php if ($algo == "4") {?>selected="true" <?php }; ?>value="4">NEATO</option>
                                                        </select>
                                                        </div>
+
                                                        <div class="gdiv">
                                                        <label class="ginput" for="rankdir">Orientation:</label>
                                                        <select class="ginput" name="rankdir">
                                                                <option <?php if ($rankdir == "1") {?>selected="true" <?php }; ?>value="1">Top to Bottom</option>
                                                        </select>
                                                        </div>
+
                                                        <div class="gdiv">
                                                        <label class="ginput" for="lines">Lines:</label>
                                                        <select class="ginput" name="lines">
                                                                <option <?php if ($lines == "0") {?>selected="true" <?php }; ?>value="0">Straight</option>
-                                                               <option <?php if ($lines == "1" || $lines == "") {?>selected="true" <?php }; ?>value="1">Curve</option>
+                                                               <option <?php if ($lines == "1") {?>selected="true" <?php }; ?>value="1">Curve</option>
                                                                <option <?php if ($lines == "2") {?>selected="true" <?php }; ?>value="2">Square</option>
-                                                               <option <?php if ($lines == "3") {?>selected="true" <?php }; ?>value="3">Polyline</option>
+                                                               <option <?php if ($lines == "3" || $lines == "") {?>selected="true" <?php }; ?>value="3">Polyline</option>
                                                        </select>
                                                        </div>
+
                                                        <div class="gdiv">
                                                        <label class="ginput" for="aggr">Grouping:</label>
                                                        <select class="ginput" name="aggr">
                                                                <option <?php if ($aggr == "1") {?>selected="true" <?php }; ?>value="1">Yes</option>
                                                        </select>
                                                        </div>
+
+                                                       <div class="gdiv">
+                                                       <label class="ginput" for="lag">LAG:</label>
+                                                       <select class="ginput" name="lag">
+                                                               <option <?php if ($lag == "0" || $lag == "") {?>selected="true" <?php }; ?>value="0">No</option>
+                                                               <option <?php if ($lag == "1") {?>selected="true" <?php }; ?>value="1">Yes</option>
+                                                       </select>
+                                                       </div>
+
+                                                       <div class="gdiv">
+                                                       <label class="ginput" for="nodesep">NodeSep:</label>
+                                                       <input type = "number" max = "10.0" min = "0.0" value = <?php if ($nodesep != "") { echo $nodesep; } else { ?>"1.0"<?php }; ?> step = "0.2" name = "nodesep" />
+                                                       </div>
+
+                                                       <div class="gdiv">
+                                                       <label class="ginput" for="ranksep">RankSep:</label>
+                                                       <input type = "number" max = "10.0" min = "0.0" value = <?php if ($ranksep != "") { echo $ranksep; } else { ?>"1.0"<?php }; ?> step = "0.2" name = "ranksep" />
+                                                       </div>
+
                                                </fieldset>
                                                </form>
                                        </div>
                                                echo "<p> Please specify the desired topology.</p>";
                                        } else
                                        {
-                                               exec("python ../plugins/draw_topo_24_estable.py ".$topo." ".$router_mode." ".$format." ".$algo." ".$rankdir." ".$lines." ".$aggr , $scriptOutput, $exitCode); //PHP waits until the called program is done
+                                               $topo = preg_replace('/\s+/', '', $topo);
+                                               exec("plugins/draw_topo_26_estable.bin ".$topo." ".$router_mode." ".$format." ".$algo." ".$rankdir." ".$lines." ".$aggr." ".$lag." ".$nodesep." ".$ranksep , $scriptOutput, $exitCode); //PHP waits until the called program is done
                                                switch($exitCode)
                                                {
                                                        case 255:
                                                                echo "<img class=\"not\" src=\"pix/not.gif\">";
                                                                break;
                                                        case 0:
-                                                               echo "<img class=\"topo\" src=\"" . $scriptOutput[count($scriptOutput)-1] . "\">";
+                                                               
+                                                               {echo "<a href=\"" . $scriptOutput[count($scriptOutput)-1] . ".graphml" . "\" download>Download GRAPHML</a>";}
+
+                                                               if ($format == "0")
+                                                               {echo "<img class=\"topo\" src=\"" . $scriptOutput[count($scriptOutput)-1] . ".png\">";}
+                                                               if ($format == "1")
+                                                               {echo "<img class=\"topo\" src=\"" . $scriptOutput[count($scriptOutput)-1] . ".svg\">";}
+
                                                                break;
                                                }
                                        }
                </div>
                <?php
        }
+?>
diff --git a/python-graph-topology/js/jquery-image.js b/python-graph-topology/js/jquery-image.js
new file mode 100755 (executable)
index 0000000..ff11fa0
--- /dev/null
@@ -0,0 +1,31 @@
+$(document).ready(function(){
+  //$('.topo').resizable({
+  //  containment: ".result"
+  //});
+
+  var helpPaneWidth = $('#help-pane').width();
+  $('#help-pane').css('margin-right', '-' + helpPaneWidth + 'px');
+
+  $('#help-button').hover(function(){
+      $(this).css('background-color', 'rgba(60, 120, 181, 0.9)')
+    },
+    function(){
+      $(this).css('background-color', 'rgba(60, 120, 181, 0.5)');
+    }
+  );
+
+  $('#help-button').click(function(){
+    if($('#help-pane').css("margin-right") == 0 + "px" && !$(this).is(':animated'))
+    {
+        $('#help-pane').animate({"margin-right": '-=' + helpPaneWidth});
+    }
+    else
+    {
+        if(!$(this).is(':animated'))//perevent double click to double margin
+        {
+            $('#help-pane').animate({"margin-right": '+=' + helpPaneWidth});
+        }
+    }
+
+  });
+});
diff --git a/python-graph-topology/readme b/python-graph-topology/readme
deleted file mode 100644 (file)
index 8c889e8..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-1) A working racktables installation is assumed. No harm can be done since all the operations towards the database are select like.
-
-2) Install the following:
-  2.0) sudo apt-get install python 
-  2.1) sudo apt-get install python-mysqldb
-  2.2) sudo apt-get install graphviz
-  2.3) sudo apt-get install python-pip
-  2.4) sudo pip install graphviz
-  
-3) Configure the IP/user/pass access data for the MySQL server in the python script:
-
-    db = MySQLdb.connect(host="127.0.0.1",     # your host, usually localhost
-                            port=3306,
-                         user="user",                  # your username
-                         passwd="pass",        # your password
-                         db="racktables")              # name of the data base
-
-4) Copy files ...
-
-4.1) Copy both the graph.php and draw_topology.py to the /var/www/racktables/plugins directory;
-4.2) Copy both logo.png and not.gif to the /var/www/racktables/wwwroot/pix directory;
-4.3) Copy gstyle.css to /var/www/racktables/plugins/css directory;
-
-5) Make sure permissions are convenient (in my setup the racktables folder belongs to www-data:www-data).
-   This is important because topologies are stored under ./wwwroot/pix/topo folder.
-
-6) In order to build a topology, properly tag all your routers with the same tag. For examples, have a look at:
-
-https://notedisabbia.wordpress.com/
-
-7) Go to the 'Topology' icon under the main page of Racktables, and invoke the tag used at step 6.
-
-enjoy!
diff --git a/python-graph-topology/sql_definitions.py b/python-graph-topology/sql_definitions.py
new file mode 100644 (file)
index 0000000..da275a6
--- /dev/null
@@ -0,0 +1,184 @@
+# Function that builds the SQL query to obtain the object Id based on name
+def fnc_build_query_objetos_name(vector):
+       query1 = ""
+       query2 = ""
+       len_vector = len(vector)
+       i = 1
+
+       query1 = (
+               "select name,id from Object where "
+               "name = '"
+       )
+
+       for row in vector:
+               if i < len_vector:
+                       query2 = query2 + row + "' or name like '"
+               else:
+                       query2 = query2 + row + "'"
+               i = i + 1
+
+       query = query1 + query2 + ";"
+
+       return query
+
+# Function that builds the SQL query to obtain the object Id based
+# on input_string
+def fnc_build_query_objetos(vector):
+       query1=""
+       query2=""
+       len_vector = len(vector)
+       i=1
+
+       query1=(
+               "select "
+               "OBJ.name as name, "
+               "TS.entity_id as id "
+               "from "
+               "TagStorage as TS join Object as OBJ on (TS.entity_id=OBJ.id) "
+               "where entity_realm ='object' and ("
+       )
+
+       for row in vector:
+               obj_id=str(row[0])
+               if i < len_vector:
+                       query2 = query2 + "tag_id = " + obj_id + " or "
+               else:
+                       query2 = query2 + "tag_id = " + obj_id + ");"
+               i=i+1
+
+       query = query1 + query2
+
+       return query
+
+# Function that builds the SQL query to obatin the topo_ID
+def fnc_build_query_topo_id(vector):
+       query1=""
+       query2=""
+       len_vector = len(vector)
+       i=1
+
+       query1=(
+               "select id from TagTree where "
+       )
+
+       for row in vector:
+               obj_id="'" + row + "'"
+               if i < len_vector:
+                       query2 = query2 + "tag = " + obj_id + " or "
+               else:
+                       query2 = query2 + "tag = " + obj_id
+               i=i+1
+
+       query = query1 + query2
+
+       return query
+
+# Function that obtains the attributes values per object ID
+# It also brings the system IP of the router.
+def fnc_build_query_attributes(df):
+
+       query1     = ""
+       query2     = ""
+       len_vector = len(df)
+
+       query1=(
+       "select "
+       "ob.name, "
+       "a.name as attrName, "
+       "av.string_value, "
+       "d.dict_value "
+
+       "from Object as ob "
+       "join AttributeValue as av on (ob.id=av.object_id) "
+       "join Attribute as a on (av.attr_id=a.id) "
+       "left join Dictionary as d on (d.dict_key=av.uint_value) "
+       "where (a.name = 'Integrado' or a.name = 'Int_Type' or a.name = 'HW type' or a.name = 'HW function' or a.name = 'TxType_CKT_ID' or a.name like '%Ref%') "
+       "and ("
+       )
+       i=1
+       for row in df.itertuples():
+               obj_id = str(row.id)
+               if i < len_vector:
+                       query2 = query2 + "ob.id = " + obj_id + " or "
+               else:
+                       query2 = query2 + "ob.id = " + obj_id
+               i=i+1
+
+       query = query1 + query2 + ")"
+
+       return query
+
+# Function that builds a SQL query to obtain the IP interfaces
+def fnc_build_query_interfaces(df):
+       query1=""
+       query2=""
+       len_vector = len(df)
+       i=1
+
+       query1=(
+       "SELECT "
+       "ro1.name AS name, "
+       "INET_NTOA(ip4.ip) as ip, "
+       "ip4.name as intName "
+
+       "FROM "
+       "Object AS ro1 "
+       "JOIN IPv4Allocation AS ip4 ON (ip4.object_id=ro1.id) "
+       "WHERE ("
+       )
+       for row in df.itertuples():
+               obj_id=str(row.id)
+               if i < len_vector:
+                       query2 = query2 + "ro1.id = " + obj_id + " or "
+               else:
+                       query2 = query2 + "ro1.id = " + obj_id
+               i=i+1
+
+       query = query1 + query2 + ")"
+
+       return query
+
+# Function that builds a SQL query to obtain the connections
+# among routers.
+def fnc_build_query_connections(df):
+
+       query1=""
+       query2=""
+       len_vector = len(df)
+       i=1
+
+       query1=(
+               "SELECT "
+               "ro1.name AS name1, "
+               "p1.name AS port1, "
+               "Link.cable, "
+               "p2.name AS port2, "
+               "ro2.name AS name2, "
+               "d1.dict_value AS obj1type, "
+               "d2.dict_value AS obj2type, "
+               "poia.oif_name as port1Speed, "
+               "poib.oif_name as port2Speed, "
+               "p1.label as intName1, "
+               "p2.label as intName2 "
+               "FROM Object AS ro1 "
+               "JOIN Port AS p1 ON(ro1.id=p1.object_id) "
+               "JOIN Link ON(p1.id=Link.porta) "
+               "JOIN Port AS p2 ON(Link.portb=p2.id) "
+               "JOIN Object AS ro2 ON(p2.object_id=ro2.id) "
+               "JOIN PortOuterInterface AS poia ON(poia.id=p1.type) "
+               "JOIN PortOuterInterface AS poib ON(poib.id=p2.type) "
+               "LEFT JOIN Dictionary AS d1 ON(ro1.objtype_id=d1.dict_key) "
+               "LEFT JOIN Dictionary AS d2 ON(ro2.objtype_id=d2.dict_key) "
+               "WHERE ("
+       )
+       for row in df.itertuples():
+               obj_id=str(row.id)
+               if i < len_vector:
+                       query2 = query2 + "ro1.id = " + obj_id + " or ro2.id = " + obj_id + " or "
+               else:
+                       query2 = query2 + "ro1.id = " + obj_id + " or ro2.id = " + obj_id
+               i=i+1
+
+       query = query1 + query2 + ")"
+
+       return query
\ No newline at end of file